xref: /aosp_15_r20/external/crosvm/src/sys/windows.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 // TODO(b:240716507): There is huge chunk for code which depends on haxm, whpx or gvm to be enabled
6*bb4ee6a4SAndroid Build Coastguard Worker // but isn't marked so. Remove this when we do so.
7*bb4ee6a4SAndroid Build Coastguard Worker #![allow(dead_code, unused_imports, unused_variables, unreachable_code)]
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) mod control_server;
10*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) mod irq_wait;
11*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) mod main;
12*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "crash-report"))]
13*bb4ee6a4SAndroid Build Coastguard Worker mod panic_hook;
14*bb4ee6a4SAndroid Build Coastguard Worker 
15*bb4ee6a4SAndroid Build Coastguard Worker mod generic;
16*bb4ee6a4SAndroid Build Coastguard Worker use generic as product;
17*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) mod run_vcpu;
18*bb4ee6a4SAndroid Build Coastguard Worker 
19*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
20*bb4ee6a4SAndroid Build Coastguard Worker use std::arch::x86_64::__cpuid;
21*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
22*bb4ee6a4SAndroid Build Coastguard Worker use std::arch::x86_64::__cpuid_count;
23*bb4ee6a4SAndroid Build Coastguard Worker use std::cmp::Reverse;
24*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
25*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::HashMap;
26*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
27*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::OpenOptions;
28*bb4ee6a4SAndroid Build Coastguard Worker use std::io::stdin;
29*bb4ee6a4SAndroid Build Coastguard Worker use std::iter;
30*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
31*bb4ee6a4SAndroid Build Coastguard Worker use std::os::windows::fs::OpenOptionsExt;
32*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
33*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc;
34*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
35*bb4ee6a4SAndroid Build Coastguard Worker 
36*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
37*bb4ee6a4SAndroid Build Coastguard Worker use aarch64::AArch64 as Arch;
38*bb4ee6a4SAndroid Build Coastguard Worker use acpi_tables::sdt::SDT;
39*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
40*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail;
41*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
42*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
43*bb4ee6a4SAndroid Build Coastguard Worker use arch::CpuConfigArch;
44*bb4ee6a4SAndroid Build Coastguard Worker use arch::DtbOverlay;
45*bb4ee6a4SAndroid Build Coastguard Worker use arch::IrqChipArch;
46*bb4ee6a4SAndroid Build Coastguard Worker use arch::LinuxArch;
47*bb4ee6a4SAndroid Build Coastguard Worker use arch::RunnableLinuxVm;
48*bb4ee6a4SAndroid Build Coastguard Worker use arch::VcpuArch;
49*bb4ee6a4SAndroid Build Coastguard Worker use arch::VirtioDeviceStub;
50*bb4ee6a4SAndroid Build Coastguard Worker use arch::VmArch;
51*bb4ee6a4SAndroid Build Coastguard Worker use arch::VmComponents;
52*bb4ee6a4SAndroid Build Coastguard Worker use arch::VmImage;
53*bb4ee6a4SAndroid Build Coastguard Worker use base::enable_high_res_timers;
54*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
55*bb4ee6a4SAndroid Build Coastguard Worker use base::info;
56*bb4ee6a4SAndroid Build Coastguard Worker use base::open_file_or_duplicate;
57*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
58*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
59*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
60*bb4ee6a4SAndroid Build Coastguard Worker use base::BlockingMode;
61*bb4ee6a4SAndroid Build Coastguard Worker use base::CloseNotifier;
62*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
63*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
64*bb4ee6a4SAndroid Build Coastguard Worker use base::EventType;
65*bb4ee6a4SAndroid Build Coastguard Worker use base::FlushOnDropTube;
66*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
67*bb4ee6a4SAndroid Build Coastguard Worker use base::FramingMode;
68*bb4ee6a4SAndroid Build Coastguard Worker use base::FromRawDescriptor;
69*bb4ee6a4SAndroid Build Coastguard Worker use base::ProtoTube;
70*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
71*bb4ee6a4SAndroid Build Coastguard Worker use base::ReadNotifier;
72*bb4ee6a4SAndroid Build Coastguard Worker use base::RecvTube;
73*bb4ee6a4SAndroid Build Coastguard Worker use base::SendTube;
74*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
75*bb4ee6a4SAndroid Build Coastguard Worker use base::StreamChannel;
76*bb4ee6a4SAndroid Build Coastguard Worker use base::Terminal;
77*bb4ee6a4SAndroid Build Coastguard Worker use base::TriggeredEvent;
78*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
79*bb4ee6a4SAndroid Build Coastguard Worker use base::TubeError;
80*bb4ee6a4SAndroid Build Coastguard Worker use base::VmEventType;
81*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
82*bb4ee6a4SAndroid Build Coastguard Worker use broker_ipc::common_child_setup;
83*bb4ee6a4SAndroid Build Coastguard Worker use broker_ipc::CommonChildStartupArgs;
84*bb4ee6a4SAndroid Build Coastguard Worker use control_server::ControlServer;
85*bb4ee6a4SAndroid Build Coastguard Worker use crosvm_cli::sys::windows::exit::Exit;
86*bb4ee6a4SAndroid Build Coastguard Worker use crosvm_cli::sys::windows::exit::ExitContext;
87*bb4ee6a4SAndroid Build Coastguard Worker use crosvm_cli::sys::windows::exit::ExitContextAnyhow;
88*bb4ee6a4SAndroid Build Coastguard Worker use crosvm_cli::sys::windows::exit::ExitContextOption;
89*bb4ee6a4SAndroid Build Coastguard Worker use devices::create_devices_worker_thread;
90*bb4ee6a4SAndroid Build Coastguard Worker use devices::serial_device::SerialHardware;
91*bb4ee6a4SAndroid Build Coastguard Worker use devices::serial_device::SerialParameters;
92*bb4ee6a4SAndroid Build Coastguard Worker use devices::tsc::get_tsc_sync_mitigations;
93*bb4ee6a4SAndroid Build Coastguard Worker use devices::tsc::standard_deviation;
94*bb4ee6a4SAndroid Build Coastguard Worker use devices::tsc::TscSyncMitigations;
95*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio;
96*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::block::DiskOption;
97*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
98*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::snd::common_backend::VirtioSnd;
99*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
100*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::snd::parameters::Parameters as SndParameters;
101*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
102*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::device::gpu::sys::windows::GpuVmmConfig;
103*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
104*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::device::gpu::sys::windows::InputEventSplitConfig;
105*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
106*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::device::gpu::sys::windows::InputEventVmmConfig;
107*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
108*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::gpu::sys::windows::product::GpuBackendConfig as GpuBackendConfigProduct;
109*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
110*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::gpu::sys::windows::run_gpu_device_worker;
111*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
112*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::snd::sys::windows::product::SndBackendConfig as SndBackendConfigProduct;
113*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
114*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::snd::sys::windows::run_snd_device_worker;
115*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
116*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::vhost::user::snd::sys::windows::SndSplitConfig;
117*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "balloon")]
118*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::BalloonFeatures;
119*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::Console;
120*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
121*bb4ee6a4SAndroid Build Coastguard Worker use devices::virtio::GpuParameters;
122*bb4ee6a4SAndroid Build Coastguard Worker use devices::BusDeviceObj;
123*bb4ee6a4SAndroid Build Coastguard Worker use devices::BusResumeDevice;
124*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
125*bb4ee6a4SAndroid Build Coastguard Worker use devices::GvmIrqChip;
126*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
127*bb4ee6a4SAndroid Build Coastguard Worker use devices::IrqChip;
128*bb4ee6a4SAndroid Build Coastguard Worker use devices::UserspaceIrqChip;
129*bb4ee6a4SAndroid Build Coastguard Worker use devices::VcpuRunState;
130*bb4ee6a4SAndroid Build Coastguard Worker use devices::VirtioPciDevice;
131*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
132*bb4ee6a4SAndroid Build Coastguard Worker use devices::WhpxSplitIrqChip;
133*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
134*bb4ee6a4SAndroid Build Coastguard Worker use gpu_display::EventDevice;
135*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
136*bb4ee6a4SAndroid Build Coastguard Worker use gpu_display::WindowProcedureThread;
137*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
138*bb4ee6a4SAndroid Build Coastguard Worker use gpu_display::WindowProcedureThreadBuilder;
139*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
140*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::gvm::Gvm;
141*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
142*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::gvm::GvmVcpu;
143*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
144*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::gvm::GvmVersion;
145*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
146*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::gvm::GvmVm;
147*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "haxm")]
148*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::haxm::get_use_ghaxm;
149*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "haxm")]
150*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::haxm::set_use_ghaxm;
151*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "haxm")]
152*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::haxm::Haxm;
153*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "haxm")]
154*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::haxm::HaxmVcpu;
155*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "haxm")]
156*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::haxm::HaxmVm;
157*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
158*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::Whpx;
159*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
160*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::WhpxFeature;
161*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
162*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::WhpxVcpu;
163*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
164*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::WhpxVm;
165*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Hypervisor;
166*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
167*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::HypervisorCap;
168*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
169*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::HypervisorX86_64;
170*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::ProtectionType;
171*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Vm;
172*bb4ee6a4SAndroid Build Coastguard Worker use irq_wait::IrqWaitWorker;
173*bb4ee6a4SAndroid Build Coastguard Worker use jail::FakeMinijailStub as Minijail;
174*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "crash-report"))]
175*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use panic_hook::set_panic_hook;
176*bb4ee6a4SAndroid Build Coastguard Worker use product::create_snd_mute_tube_pair;
177*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(feature = "haxm", feature = "gvm", feature = "whpx"))]
178*bb4ee6a4SAndroid Build Coastguard Worker use product::create_snd_state_tube;
179*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "pvclock")]
180*bb4ee6a4SAndroid Build Coastguard Worker use product::handle_pvclock_request;
181*bb4ee6a4SAndroid Build Coastguard Worker use product::merge_session_invariants;
182*bb4ee6a4SAndroid Build Coastguard Worker use product::run_ime_thread;
183*bb4ee6a4SAndroid Build Coastguard Worker use product::set_package_name;
184*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use product::setup_metrics_reporting;
185*bb4ee6a4SAndroid Build Coastguard Worker use product::start_service_ipc_listener;
186*bb4ee6a4SAndroid Build Coastguard Worker use product::RunControlArgs;
187*bb4ee6a4SAndroid Build Coastguard Worker use product::ServiceVmState;
188*bb4ee6a4SAndroid Build Coastguard Worker use product::Token;
189*bb4ee6a4SAndroid Build Coastguard Worker use resources::SystemAllocator;
190*bb4ee6a4SAndroid Build Coastguard Worker use run_vcpu::run_all_vcpus;
191*bb4ee6a4SAndroid Build Coastguard Worker use run_vcpu::VcpuRunMode;
192*bb4ee6a4SAndroid Build Coastguard Worker use rutabaga_gfx::RutabagaGralloc;
193*bb4ee6a4SAndroid Build Coastguard Worker use rutabaga_gfx::RutabagaGrallocBackendFlags;
194*bb4ee6a4SAndroid Build Coastguard Worker use smallvec::SmallVec;
195*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
196*bb4ee6a4SAndroid Build Coastguard Worker use tube_transporter::TubeToken;
197*bb4ee6a4SAndroid Build Coastguard Worker use tube_transporter::TubeTransporterReader;
198*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::api::VmMemoryClient;
199*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "balloon")]
200*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::BalloonControlCommand;
201*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "balloon")]
202*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::BalloonTube;
203*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::DeviceControlCommand;
204*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::InitialAudioSessionState;
205*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::IrqHandlerRequest;
206*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::PvClockCommand;
207*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VcpuControl;
208*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmMemoryRegionState;
209*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmMemoryRequest;
210*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmRequest;
211*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmResponse;
212*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmRunMode;
213*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
214*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
215*bb4ee6a4SAndroid Build Coastguard Worker use vmm_vhost::Connection;
216*bb4ee6a4SAndroid Build Coastguard Worker use vmm_vhost::FrontendReq;
217*bb4ee6a4SAndroid Build Coastguard Worker use win_util::ProcessType;
218*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
219*bb4ee6a4SAndroid Build Coastguard Worker use x86_64::cpuid::adjust_cpuid;
220*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
221*bb4ee6a4SAndroid Build Coastguard Worker use x86_64::cpuid::CpuIdContext;
222*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")]
223*bb4ee6a4SAndroid Build Coastguard Worker use x86_64::X8664arch as Arch;
224*bb4ee6a4SAndroid Build Coastguard Worker 
225*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::config::Config;
226*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::config::Executable;
227*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::config::InputDeviceOption;
228*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(feature = "gvm", feature = "whpx"))]
229*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::config::IrqChipKind;
230*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
231*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::config::TouchDeviceOption;
232*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::config::DEFAULT_TOUCH_DEVICE_HEIGHT;
233*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::config::DEFAULT_TOUCH_DEVICE_WIDTH;
234*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::sys::config::HypervisorKind;
235*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::sys::windows::broker::BrokerTubes;
236*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "stats")]
237*bb4ee6a4SAndroid Build Coastguard Worker use crate::crosvm::sys::windows::stats::StatisticsCollector;
238*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
239*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use crate::sys::windows::product::get_gpu_product_configs;
240*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
241*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use crate::sys::windows::product::get_snd_product_configs;
242*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
243*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use crate::sys::windows::product::get_window_procedure_thread_product_configs;
244*bb4ee6a4SAndroid Build Coastguard Worker use crate::sys::windows::product::log_descriptor;
245*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
246*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use crate::sys::windows::product::num_input_sound_devices;
247*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
248*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) use crate::sys::windows::product::num_input_sound_streams;
249*bb4ee6a4SAndroid Build Coastguard Worker use crate::sys::windows::product::spawn_anti_tamper_thread;
250*bb4ee6a4SAndroid Build Coastguard Worker use crate::sys::windows::product::MetricEventType;
251*bb4ee6a4SAndroid Build Coastguard Worker 
252*bb4ee6a4SAndroid Build Coastguard Worker const DEFAULT_GUEST_CID: u64 = 3;
253*bb4ee6a4SAndroid Build Coastguard Worker 
254*bb4ee6a4SAndroid Build Coastguard Worker // by default, if enabled, the balloon WS features will use 4 bins.
255*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_WS_DEFAULT_NUM_BINS: u8 = 4;
256*bb4ee6a4SAndroid Build Coastguard Worker 
257*bb4ee6a4SAndroid Build Coastguard Worker enum TaggedControlTube {
258*bb4ee6a4SAndroid Build Coastguard Worker     Vm(FlushOnDropTube),
259*bb4ee6a4SAndroid Build Coastguard Worker     Product(product::TaggedControlTube),
260*bb4ee6a4SAndroid Build Coastguard Worker }
261*bb4ee6a4SAndroid Build Coastguard Worker 
262*bb4ee6a4SAndroid Build Coastguard Worker impl ReadNotifier for TaggedControlTube {
263*bb4ee6a4SAndroid Build Coastguard Worker     fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
264*bb4ee6a4SAndroid Build Coastguard Worker         match self {
265*bb4ee6a4SAndroid Build Coastguard Worker             Self::Vm(tube) => tube.0.get_read_notifier(),
266*bb4ee6a4SAndroid Build Coastguard Worker             Self::Product(tube) => tube.get_read_notifier(),
267*bb4ee6a4SAndroid Build Coastguard Worker         }
268*bb4ee6a4SAndroid Build Coastguard Worker     }
269*bb4ee6a4SAndroid Build Coastguard Worker }
270*bb4ee6a4SAndroid Build Coastguard Worker 
271*bb4ee6a4SAndroid Build Coastguard Worker impl CloseNotifier for TaggedControlTube {
272*bb4ee6a4SAndroid Build Coastguard Worker     fn get_close_notifier(&self) -> &dyn AsRawDescriptor {
273*bb4ee6a4SAndroid Build Coastguard Worker         match self {
274*bb4ee6a4SAndroid Build Coastguard Worker             Self::Vm(tube) => tube.0.get_close_notifier(),
275*bb4ee6a4SAndroid Build Coastguard Worker             Self::Product(tube) => tube.get_close_notifier(),
276*bb4ee6a4SAndroid Build Coastguard Worker         }
277*bb4ee6a4SAndroid Build Coastguard Worker     }
278*bb4ee6a4SAndroid Build Coastguard Worker }
279*bb4ee6a4SAndroid Build Coastguard Worker 
280*bb4ee6a4SAndroid Build Coastguard Worker pub enum ExitState {
281*bb4ee6a4SAndroid Build Coastguard Worker     Reset,
282*bb4ee6a4SAndroid Build Coastguard Worker     Stop,
283*bb4ee6a4SAndroid Build Coastguard Worker     Crash,
284*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(dead_code)]
285*bb4ee6a4SAndroid Build Coastguard Worker     GuestPanic,
286*bb4ee6a4SAndroid Build Coastguard Worker     WatchdogReset,
287*bb4ee6a4SAndroid Build Coastguard Worker }
288*bb4ee6a4SAndroid Build Coastguard Worker 
289*bb4ee6a4SAndroid Build Coastguard Worker type DeviceResult<T = VirtioDeviceStub> = Result<T>;
290*bb4ee6a4SAndroid Build Coastguard Worker 
291*bb4ee6a4SAndroid Build Coastguard Worker fn create_vhost_user_block_device(
292*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &Config,
293*bb4ee6a4SAndroid Build Coastguard Worker     connection: Connection<FrontendReq>,
294*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult {
295*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::VhostUserFrontend::new(
296*bb4ee6a4SAndroid Build Coastguard Worker         virtio::DeviceType::Block,
297*bb4ee6a4SAndroid Build Coastguard Worker         virtio::base_features(cfg.protection_type),
298*bb4ee6a4SAndroid Build Coastguard Worker         connection,
299*bb4ee6a4SAndroid Build Coastguard Worker         None,
300*bb4ee6a4SAndroid Build Coastguard Worker         None,
301*bb4ee6a4SAndroid Build Coastguard Worker     )
302*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(
303*bb4ee6a4SAndroid Build Coastguard Worker         Exit::VhostUserBlockDeviceNew,
304*bb4ee6a4SAndroid Build Coastguard Worker         "failed to set up vhost-user block device",
305*bb4ee6a4SAndroid Build Coastguard Worker     )?;
306*bb4ee6a4SAndroid Build Coastguard Worker 
307*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
308*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
309*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
310*bb4ee6a4SAndroid Build Coastguard Worker     })
311*bb4ee6a4SAndroid Build Coastguard Worker }
312*bb4ee6a4SAndroid Build Coastguard Worker 
313*bb4ee6a4SAndroid Build Coastguard Worker fn create_block_device(cfg: &Config, disk: &DiskOption, disk_device_tube: Tube) -> DeviceResult {
314*bb4ee6a4SAndroid Build Coastguard Worker     let features = virtio::base_features(cfg.protection_type);
315*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::BlockAsync::new(
316*bb4ee6a4SAndroid Build Coastguard Worker         features,
317*bb4ee6a4SAndroid Build Coastguard Worker         disk.open()?,
318*bb4ee6a4SAndroid Build Coastguard Worker         disk,
319*bb4ee6a4SAndroid Build Coastguard Worker         Some(disk_device_tube),
320*bb4ee6a4SAndroid Build Coastguard Worker         None,
321*bb4ee6a4SAndroid Build Coastguard Worker         None,
322*bb4ee6a4SAndroid Build Coastguard Worker     )
323*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(Exit::BlockDeviceNew, "failed to create block device")?;
324*bb4ee6a4SAndroid Build Coastguard Worker 
325*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
326*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
327*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
328*bb4ee6a4SAndroid Build Coastguard Worker     })
329*bb4ee6a4SAndroid Build Coastguard Worker }
330*bb4ee6a4SAndroid Build Coastguard Worker 
331*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
332*bb4ee6a4SAndroid Build Coastguard Worker fn create_vhost_user_gpu_device(
333*bb4ee6a4SAndroid Build Coastguard Worker     base_features: u64,
334*bb4ee6a4SAndroid Build Coastguard Worker     connection: Connection<FrontendReq>,
335*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult {
336*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::VhostUserFrontend::new(
337*bb4ee6a4SAndroid Build Coastguard Worker         virtio::DeviceType::Gpu,
338*bb4ee6a4SAndroid Build Coastguard Worker         base_features,
339*bb4ee6a4SAndroid Build Coastguard Worker         connection,
340*bb4ee6a4SAndroid Build Coastguard Worker         None,
341*bb4ee6a4SAndroid Build Coastguard Worker         None,
342*bb4ee6a4SAndroid Build Coastguard Worker     )
343*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(
344*bb4ee6a4SAndroid Build Coastguard Worker         Exit::VhostUserGpuDeviceNew,
345*bb4ee6a4SAndroid Build Coastguard Worker         "failed to set up vhost-user gpu device",
346*bb4ee6a4SAndroid Build Coastguard Worker     )?;
347*bb4ee6a4SAndroid Build Coastguard Worker 
348*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
349*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
350*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
351*bb4ee6a4SAndroid Build Coastguard Worker     })
352*bb4ee6a4SAndroid Build Coastguard Worker }
353*bb4ee6a4SAndroid Build Coastguard Worker 
354*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
355*bb4ee6a4SAndroid Build Coastguard Worker fn create_vhost_user_snd_device(
356*bb4ee6a4SAndroid Build Coastguard Worker     base_features: u64,
357*bb4ee6a4SAndroid Build Coastguard Worker     connection: Connection<FrontendReq>,
358*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult {
359*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::VhostUserFrontend::new(
360*bb4ee6a4SAndroid Build Coastguard Worker         virtio::DeviceType::Sound,
361*bb4ee6a4SAndroid Build Coastguard Worker         base_features,
362*bb4ee6a4SAndroid Build Coastguard Worker         connection,
363*bb4ee6a4SAndroid Build Coastguard Worker         None,
364*bb4ee6a4SAndroid Build Coastguard Worker         None,
365*bb4ee6a4SAndroid Build Coastguard Worker     )
366*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(
367*bb4ee6a4SAndroid Build Coastguard Worker         Exit::VhostUserSndDeviceNew,
368*bb4ee6a4SAndroid Build Coastguard Worker         "failed to set up vhost-user snd device",
369*bb4ee6a4SAndroid Build Coastguard Worker     )?;
370*bb4ee6a4SAndroid Build Coastguard Worker 
371*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
372*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
373*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
374*bb4ee6a4SAndroid Build Coastguard Worker     })
375*bb4ee6a4SAndroid Build Coastguard Worker }
376*bb4ee6a4SAndroid Build Coastguard Worker 
377*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
378*bb4ee6a4SAndroid Build Coastguard Worker fn create_multi_touch_device(
379*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &Config,
380*bb4ee6a4SAndroid Build Coastguard Worker     event_pipe: StreamChannel,
381*bb4ee6a4SAndroid Build Coastguard Worker     width: u32,
382*bb4ee6a4SAndroid Build Coastguard Worker     height: u32,
383*bb4ee6a4SAndroid Build Coastguard Worker     name: Option<&str>,
384*bb4ee6a4SAndroid Build Coastguard Worker     idx: u32,
385*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult {
386*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::input::new_multi_touch(
387*bb4ee6a4SAndroid Build Coastguard Worker         idx,
388*bb4ee6a4SAndroid Build Coastguard Worker         event_pipe,
389*bb4ee6a4SAndroid Build Coastguard Worker         width,
390*bb4ee6a4SAndroid Build Coastguard Worker         height,
391*bb4ee6a4SAndroid Build Coastguard Worker         name,
392*bb4ee6a4SAndroid Build Coastguard Worker         virtio::base_features(cfg.protection_type),
393*bb4ee6a4SAndroid Build Coastguard Worker     )
394*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(Exit::InputDeviceNew, "failed to set up input device")?;
395*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
396*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
397*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
398*bb4ee6a4SAndroid Build Coastguard Worker     })
399*bb4ee6a4SAndroid Build Coastguard Worker }
400*bb4ee6a4SAndroid Build Coastguard Worker 
401*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
402*bb4ee6a4SAndroid Build Coastguard Worker fn create_mouse_device(cfg: &Config, event_pipe: StreamChannel, idx: u32) -> DeviceResult {
403*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::input::new_mouse(idx, event_pipe, virtio::base_features(cfg.protection_type))
404*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::InputDeviceNew, "failed to set up input device")?;
405*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
406*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
407*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
408*bb4ee6a4SAndroid Build Coastguard Worker     })
409*bb4ee6a4SAndroid Build Coastguard Worker }
410*bb4ee6a4SAndroid Build Coastguard Worker 
411*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "slirp")]
412*bb4ee6a4SAndroid Build Coastguard Worker fn create_vhost_user_net_device(cfg: &Config, connection: Connection<FrontendReq>) -> DeviceResult {
413*bb4ee6a4SAndroid Build Coastguard Worker     let features = virtio::base_features(cfg.protection_type);
414*bb4ee6a4SAndroid Build Coastguard Worker     let dev =
415*bb4ee6a4SAndroid Build Coastguard Worker         virtio::VhostUserFrontend::new(virtio::DeviceType::Net, features, connection, None, None)
416*bb4ee6a4SAndroid Build Coastguard Worker             .exit_context(
417*bb4ee6a4SAndroid Build Coastguard Worker             Exit::VhostUserNetDeviceNew,
418*bb4ee6a4SAndroid Build Coastguard Worker             "failed to set up vhost-user net device",
419*bb4ee6a4SAndroid Build Coastguard Worker         )?;
420*bb4ee6a4SAndroid Build Coastguard Worker 
421*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
422*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
423*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
424*bb4ee6a4SAndroid Build Coastguard Worker     })
425*bb4ee6a4SAndroid Build Coastguard Worker }
426*bb4ee6a4SAndroid Build Coastguard Worker 
427*bb4ee6a4SAndroid Build Coastguard Worker fn create_rng_device(cfg: &Config) -> DeviceResult {
428*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::Rng::new(virtio::base_features(cfg.protection_type))
429*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::RngDeviceNew, "failed to set up rng")?;
430*bb4ee6a4SAndroid Build Coastguard Worker 
431*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
432*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
433*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
434*bb4ee6a4SAndroid Build Coastguard Worker     })
435*bb4ee6a4SAndroid Build Coastguard Worker }
436*bb4ee6a4SAndroid Build Coastguard Worker 
437*bb4ee6a4SAndroid Build Coastguard Worker fn create_console_device(cfg: &Config, param: &SerialParameters) -> DeviceResult {
438*bb4ee6a4SAndroid Build Coastguard Worker     let mut keep_rds = Vec::new();
439*bb4ee6a4SAndroid Build Coastguard Worker     let evt = Event::new().exit_context(Exit::CreateEvent, "failed to create event")?;
440*bb4ee6a4SAndroid Build Coastguard Worker     let dev = param
441*bb4ee6a4SAndroid Build Coastguard Worker         .create_serial_device::<Console>(cfg.protection_type, &evt, &mut keep_rds)
442*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::CreateConsole, "failed to create console device")?;
443*bb4ee6a4SAndroid Build Coastguard Worker 
444*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
445*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
446*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
447*bb4ee6a4SAndroid Build Coastguard Worker     })
448*bb4ee6a4SAndroid Build Coastguard Worker }
449*bb4ee6a4SAndroid Build Coastguard Worker 
450*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "balloon")]
451*bb4ee6a4SAndroid Build Coastguard Worker fn create_balloon_device(
452*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &Config,
453*bb4ee6a4SAndroid Build Coastguard Worker     balloon_device_tube: Tube,
454*bb4ee6a4SAndroid Build Coastguard Worker     dynamic_mapping_device_tube: Tube,
455*bb4ee6a4SAndroid Build Coastguard Worker     inflate_tube: Option<Tube>,
456*bb4ee6a4SAndroid Build Coastguard Worker     init_balloon_size: u64,
457*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult {
458*bb4ee6a4SAndroid Build Coastguard Worker     let balloon_features =
459*bb4ee6a4SAndroid Build Coastguard Worker         (cfg.balloon_page_reporting as u64) << BalloonFeatures::PageReporting as u64;
460*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::Balloon::new(
461*bb4ee6a4SAndroid Build Coastguard Worker         virtio::base_features(cfg.protection_type),
462*bb4ee6a4SAndroid Build Coastguard Worker         balloon_device_tube,
463*bb4ee6a4SAndroid Build Coastguard Worker         VmMemoryClient::new(dynamic_mapping_device_tube),
464*bb4ee6a4SAndroid Build Coastguard Worker         inflate_tube,
465*bb4ee6a4SAndroid Build Coastguard Worker         init_balloon_size,
466*bb4ee6a4SAndroid Build Coastguard Worker         balloon_features,
467*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "registered_events")]
468*bb4ee6a4SAndroid Build Coastguard Worker         None,
469*bb4ee6a4SAndroid Build Coastguard Worker         VIRTIO_BALLOON_WS_DEFAULT_NUM_BINS,
470*bb4ee6a4SAndroid Build Coastguard Worker     )
471*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(Exit::BalloonDeviceNew, "failed to create balloon")?;
472*bb4ee6a4SAndroid Build Coastguard Worker 
473*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
474*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
475*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
476*bb4ee6a4SAndroid Build Coastguard Worker     })
477*bb4ee6a4SAndroid Build Coastguard Worker }
478*bb4ee6a4SAndroid Build Coastguard Worker 
479*bb4ee6a4SAndroid Build Coastguard Worker fn create_vsock_device(cfg: &Config) -> DeviceResult {
480*bb4ee6a4SAndroid Build Coastguard Worker     // We only support a single guest, so we can confidently assign a default
481*bb4ee6a4SAndroid Build Coastguard Worker     // CID if one isn't provided. We choose the lowest non-reserved value.
482*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::vsock::Vsock::new(
483*bb4ee6a4SAndroid Build Coastguard Worker         cfg.vsock
484*bb4ee6a4SAndroid Build Coastguard Worker             .as_ref()
485*bb4ee6a4SAndroid Build Coastguard Worker             .map(|cfg| cfg.cid)
486*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap_or(DEFAULT_GUEST_CID),
487*bb4ee6a4SAndroid Build Coastguard Worker         cfg.host_guid.clone(),
488*bb4ee6a4SAndroid Build Coastguard Worker         virtio::base_features(cfg.protection_type),
489*bb4ee6a4SAndroid Build Coastguard Worker     )
490*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(
491*bb4ee6a4SAndroid Build Coastguard Worker         Exit::UserspaceVsockDeviceNew,
492*bb4ee6a4SAndroid Build Coastguard Worker         "failed to create userspace vsock device",
493*bb4ee6a4SAndroid Build Coastguard Worker     )?;
494*bb4ee6a4SAndroid Build Coastguard Worker 
495*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VirtioDeviceStub {
496*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
497*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
498*bb4ee6a4SAndroid Build Coastguard Worker     })
499*bb4ee6a4SAndroid Build Coastguard Worker }
500*bb4ee6a4SAndroid Build Coastguard Worker 
501*bb4ee6a4SAndroid Build Coastguard Worker fn create_virtio_devices(
502*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &mut Config,
503*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_wrtube: &SendTube,
504*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(clippy::ptr_arg)] control_tubes: &mut Vec<TaggedControlTube>,
505*bb4ee6a4SAndroid Build Coastguard Worker     disk_device_tubes: &mut Vec<Tube>,
506*bb4ee6a4SAndroid Build Coastguard Worker     initial_audio_session_states: &mut Vec<InitialAudioSessionState>,
507*bb4ee6a4SAndroid Build Coastguard Worker     balloon_device_tube: Option<Tube>,
508*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")] pvclock_device_tube: Option<Tube>,
509*bb4ee6a4SAndroid Build Coastguard Worker     dynamic_mapping_device_tube: Option<Tube>,
510*bb4ee6a4SAndroid Build Coastguard Worker     inflate_tube: Option<Tube>,
511*bb4ee6a4SAndroid Build Coastguard Worker     init_balloon_size: u64,
512*bb4ee6a4SAndroid Build Coastguard Worker     tsc_frequency: u64,
513*bb4ee6a4SAndroid Build Coastguard Worker     virtio_snd_state_device_tube: Option<Tube>,
514*bb4ee6a4SAndroid Build Coastguard Worker     virtio_snd_control_device_tube: Option<Tube>,
515*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult<Vec<VirtioDeviceStub>> {
516*bb4ee6a4SAndroid Build Coastguard Worker     let mut devs = Vec::new();
517*bb4ee6a4SAndroid Build Coastguard Worker 
518*bb4ee6a4SAndroid Build Coastguard Worker     if cfg.block_vhost_user_tube.is_empty() {
519*bb4ee6a4SAndroid Build Coastguard Worker         // Disk devices must precede virtio-console devices or the kernel does not boot.
520*bb4ee6a4SAndroid Build Coastguard Worker         // TODO(b/171215421): figure out why this ordering is required and fix it.
521*bb4ee6a4SAndroid Build Coastguard Worker         for disk in &cfg.disks {
522*bb4ee6a4SAndroid Build Coastguard Worker             let disk_device_tube = disk_device_tubes.remove(0);
523*bb4ee6a4SAndroid Build Coastguard Worker             devs.push(create_block_device(cfg, disk, disk_device_tube)?);
524*bb4ee6a4SAndroid Build Coastguard Worker         }
525*bb4ee6a4SAndroid Build Coastguard Worker     } else {
526*bb4ee6a4SAndroid Build Coastguard Worker         info!("Starting up vhost user block backends...");
527*bb4ee6a4SAndroid Build Coastguard Worker         for _disk in &cfg.disks {
528*bb4ee6a4SAndroid Build Coastguard Worker             let disk_device_tube = cfg.block_vhost_user_tube.remove(0);
529*bb4ee6a4SAndroid Build Coastguard Worker             let connection = Connection::<FrontendReq>::from(disk_device_tube);
530*bb4ee6a4SAndroid Build Coastguard Worker             devs.push(create_vhost_user_block_device(cfg, connection)?);
531*bb4ee6a4SAndroid Build Coastguard Worker         }
532*bb4ee6a4SAndroid Build Coastguard Worker     }
533*bb4ee6a4SAndroid Build Coastguard Worker 
534*bb4ee6a4SAndroid Build Coastguard Worker     for (_, param) in cfg
535*bb4ee6a4SAndroid Build Coastguard Worker         .serial_parameters
536*bb4ee6a4SAndroid Build Coastguard Worker         .iter()
537*bb4ee6a4SAndroid Build Coastguard Worker         .filter(|(_k, v)| v.hardware == SerialHardware::VirtioConsole)
538*bb4ee6a4SAndroid Build Coastguard Worker     {
539*bb4ee6a4SAndroid Build Coastguard Worker         let dev = create_console_device(cfg, param)?;
540*bb4ee6a4SAndroid Build Coastguard Worker         devs.push(dev);
541*bb4ee6a4SAndroid Build Coastguard Worker     }
542*bb4ee6a4SAndroid Build Coastguard Worker 
543*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "audio")]
544*bb4ee6a4SAndroid Build Coastguard Worker     {
545*bb4ee6a4SAndroid Build Coastguard Worker         let snd_split_configs = std::mem::take(&mut cfg.snd_split_configs);
546*bb4ee6a4SAndroid Build Coastguard Worker         for mut snd_split_cfg in snd_split_configs.into_iter() {
547*bb4ee6a4SAndroid Build Coastguard Worker             devs.push(create_virtio_snd_device(
548*bb4ee6a4SAndroid Build Coastguard Worker                 cfg,
549*bb4ee6a4SAndroid Build Coastguard Worker                 &mut snd_split_cfg,
550*bb4ee6a4SAndroid Build Coastguard Worker                 control_tubes,
551*bb4ee6a4SAndroid Build Coastguard Worker             )?);
552*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(vmm_config) = snd_split_cfg.vmm_config {
553*bb4ee6a4SAndroid Build Coastguard Worker                 let initial_audio_session_state = InitialAudioSessionState {
554*bb4ee6a4SAndroid Build Coastguard Worker                     audio_client_guid: vmm_config.audio_client_guid,
555*bb4ee6a4SAndroid Build Coastguard Worker                     card_index: vmm_config.card_index,
556*bb4ee6a4SAndroid Build Coastguard Worker                 };
557*bb4ee6a4SAndroid Build Coastguard Worker                 initial_audio_session_states.push(initial_audio_session_state);
558*bb4ee6a4SAndroid Build Coastguard Worker             }
559*bb4ee6a4SAndroid Build Coastguard Worker         }
560*bb4ee6a4SAndroid Build Coastguard Worker     }
561*bb4ee6a4SAndroid Build Coastguard Worker 
562*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")]
563*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(tube) = pvclock_device_tube {
564*bb4ee6a4SAndroid Build Coastguard Worker         product::push_pvclock_device(cfg, &mut devs, tsc_frequency, tube);
565*bb4ee6a4SAndroid Build Coastguard Worker     }
566*bb4ee6a4SAndroid Build Coastguard Worker 
567*bb4ee6a4SAndroid Build Coastguard Worker     devs.push(create_rng_device(cfg)?);
568*bb4ee6a4SAndroid Build Coastguard Worker 
569*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "slirp")]
570*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(net_vhost_user_tube) = cfg.net_vhost_user_tube.take() {
571*bb4ee6a4SAndroid Build Coastguard Worker         let connection = Connection::<FrontendReq>::from(net_vhost_user_tube);
572*bb4ee6a4SAndroid Build Coastguard Worker         devs.push(create_vhost_user_net_device(cfg, connection)?);
573*bb4ee6a4SAndroid Build Coastguard Worker     }
574*bb4ee6a4SAndroid Build Coastguard Worker 
575*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "balloon")]
576*bb4ee6a4SAndroid Build Coastguard Worker     if let (Some(balloon_device_tube), Some(dynamic_mapping_device_tube)) =
577*bb4ee6a4SAndroid Build Coastguard Worker         (balloon_device_tube, dynamic_mapping_device_tube)
578*bb4ee6a4SAndroid Build Coastguard Worker     {
579*bb4ee6a4SAndroid Build Coastguard Worker         devs.push(create_balloon_device(
580*bb4ee6a4SAndroid Build Coastguard Worker             cfg,
581*bb4ee6a4SAndroid Build Coastguard Worker             balloon_device_tube,
582*bb4ee6a4SAndroid Build Coastguard Worker             dynamic_mapping_device_tube,
583*bb4ee6a4SAndroid Build Coastguard Worker             inflate_tube,
584*bb4ee6a4SAndroid Build Coastguard Worker             init_balloon_size,
585*bb4ee6a4SAndroid Build Coastguard Worker         )?);
586*bb4ee6a4SAndroid Build Coastguard Worker     }
587*bb4ee6a4SAndroid Build Coastguard Worker 
588*bb4ee6a4SAndroid Build Coastguard Worker     devs.push(create_vsock_device(cfg)?);
589*bb4ee6a4SAndroid Build Coastguard Worker 
590*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gpu")]
591*bb4ee6a4SAndroid Build Coastguard Worker     let event_devices = if let Some(InputEventSplitConfig {
592*bb4ee6a4SAndroid Build Coastguard Worker         backend_config,
593*bb4ee6a4SAndroid Build Coastguard Worker         vmm_config,
594*bb4ee6a4SAndroid Build Coastguard Worker     }) = cfg.input_event_split_config.take()
595*bb4ee6a4SAndroid Build Coastguard Worker     {
596*bb4ee6a4SAndroid Build Coastguard Worker         devs.extend(
597*bb4ee6a4SAndroid Build Coastguard Worker             create_virtio_input_event_devices(cfg, vmm_config)
598*bb4ee6a4SAndroid Build Coastguard Worker                 .context("create input event devices")?,
599*bb4ee6a4SAndroid Build Coastguard Worker         );
600*bb4ee6a4SAndroid Build Coastguard Worker         backend_config.map(|cfg| cfg.event_devices)
601*bb4ee6a4SAndroid Build Coastguard Worker     } else {
602*bb4ee6a4SAndroid Build Coastguard Worker         None
603*bb4ee6a4SAndroid Build Coastguard Worker     };
604*bb4ee6a4SAndroid Build Coastguard Worker 
605*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gpu")]
606*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(wndproc_thread_vmm_config) = cfg
607*bb4ee6a4SAndroid Build Coastguard Worker         .window_procedure_thread_split_config
608*bb4ee6a4SAndroid Build Coastguard Worker         .as_mut()
609*bb4ee6a4SAndroid Build Coastguard Worker         .map(|split_cfg| &mut split_cfg.vmm_config)
610*bb4ee6a4SAndroid Build Coastguard Worker     {
611*bb4ee6a4SAndroid Build Coastguard Worker         product::push_window_procedure_thread_control_tubes(
612*bb4ee6a4SAndroid Build Coastguard Worker             control_tubes,
613*bb4ee6a4SAndroid Build Coastguard Worker             wndproc_thread_vmm_config,
614*bb4ee6a4SAndroid Build Coastguard Worker         );
615*bb4ee6a4SAndroid Build Coastguard Worker     }
616*bb4ee6a4SAndroid Build Coastguard Worker 
617*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gpu")]
618*bb4ee6a4SAndroid Build Coastguard Worker     let mut wndproc_thread = cfg
619*bb4ee6a4SAndroid Build Coastguard Worker         .window_procedure_thread_split_config
620*bb4ee6a4SAndroid Build Coastguard Worker         .as_mut()
621*bb4ee6a4SAndroid Build Coastguard Worker         .and_then(|cfg| cfg.wndproc_thread_builder.take())
622*bb4ee6a4SAndroid Build Coastguard Worker         .map(WindowProcedureThreadBuilder::start_thread)
623*bb4ee6a4SAndroid Build Coastguard Worker         .transpose()
624*bb4ee6a4SAndroid Build Coastguard Worker         .context("Failed to start the window procedure thread.")?;
625*bb4ee6a4SAndroid Build Coastguard Worker 
626*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gpu")]
627*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(gpu_vmm_config) = cfg.gpu_vmm_config.take() {
628*bb4ee6a4SAndroid Build Coastguard Worker         devs.push(create_virtio_gpu_device(
629*bb4ee6a4SAndroid Build Coastguard Worker             cfg,
630*bb4ee6a4SAndroid Build Coastguard Worker             gpu_vmm_config,
631*bb4ee6a4SAndroid Build Coastguard Worker             event_devices,
632*bb4ee6a4SAndroid Build Coastguard Worker             &mut wndproc_thread,
633*bb4ee6a4SAndroid Build Coastguard Worker             control_tubes,
634*bb4ee6a4SAndroid Build Coastguard Worker         )?);
635*bb4ee6a4SAndroid Build Coastguard Worker     }
636*bb4ee6a4SAndroid Build Coastguard Worker 
637*bb4ee6a4SAndroid Build Coastguard Worker     Ok(devs)
638*bb4ee6a4SAndroid Build Coastguard Worker }
639*bb4ee6a4SAndroid Build Coastguard Worker 
640*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
641*bb4ee6a4SAndroid Build Coastguard Worker fn create_virtio_input_event_devices(
642*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &Config,
643*bb4ee6a4SAndroid Build Coastguard Worker     mut input_event_vmm_config: InputEventVmmConfig,
644*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult<Vec<VirtioDeviceStub>> {
645*bb4ee6a4SAndroid Build Coastguard Worker     let mut devs = Vec::new();
646*bb4ee6a4SAndroid Build Coastguard Worker 
647*bb4ee6a4SAndroid Build Coastguard Worker     // Iterate event devices, create the VMM end.
648*bb4ee6a4SAndroid Build Coastguard Worker     let mut multi_touch_pipes = input_event_vmm_config
649*bb4ee6a4SAndroid Build Coastguard Worker         .multi_touch_pipes
650*bb4ee6a4SAndroid Build Coastguard Worker         .drain(..)
651*bb4ee6a4SAndroid Build Coastguard Worker         .enumerate();
652*bb4ee6a4SAndroid Build Coastguard Worker     for input in &cfg.virtio_input {
653*bb4ee6a4SAndroid Build Coastguard Worker         match input {
654*bb4ee6a4SAndroid Build Coastguard Worker             InputDeviceOption::SingleTouch { .. } => {
655*bb4ee6a4SAndroid Build Coastguard Worker                 unimplemented!("--single-touch is no longer supported. Use --multi-touch instead.");
656*bb4ee6a4SAndroid Build Coastguard Worker             }
657*bb4ee6a4SAndroid Build Coastguard Worker             InputDeviceOption::MultiTouch {
658*bb4ee6a4SAndroid Build Coastguard Worker                 width,
659*bb4ee6a4SAndroid Build Coastguard Worker                 height,
660*bb4ee6a4SAndroid Build Coastguard Worker                 name,
661*bb4ee6a4SAndroid Build Coastguard Worker                 ..
662*bb4ee6a4SAndroid Build Coastguard Worker             } => {
663*bb4ee6a4SAndroid Build Coastguard Worker                 let Some((idx, pipe)) = multi_touch_pipes.next() else {
664*bb4ee6a4SAndroid Build Coastguard Worker                     break;
665*bb4ee6a4SAndroid Build Coastguard Worker                 };
666*bb4ee6a4SAndroid Build Coastguard Worker                 let mut width = *width;
667*bb4ee6a4SAndroid Build Coastguard Worker                 let mut height = *height;
668*bb4ee6a4SAndroid Build Coastguard Worker                 if idx == 0 {
669*bb4ee6a4SAndroid Build Coastguard Worker                     if width.is_none() {
670*bb4ee6a4SAndroid Build Coastguard Worker                         width = cfg.display_input_width;
671*bb4ee6a4SAndroid Build Coastguard Worker                     }
672*bb4ee6a4SAndroid Build Coastguard Worker                     if height.is_none() {
673*bb4ee6a4SAndroid Build Coastguard Worker                         height = cfg.display_input_height;
674*bb4ee6a4SAndroid Build Coastguard Worker                     }
675*bb4ee6a4SAndroid Build Coastguard Worker                 }
676*bb4ee6a4SAndroid Build Coastguard Worker                 devs.push(create_multi_touch_device(
677*bb4ee6a4SAndroid Build Coastguard Worker                     cfg,
678*bb4ee6a4SAndroid Build Coastguard Worker                     pipe,
679*bb4ee6a4SAndroid Build Coastguard Worker                     width.unwrap_or(DEFAULT_TOUCH_DEVICE_WIDTH),
680*bb4ee6a4SAndroid Build Coastguard Worker                     height.unwrap_or(DEFAULT_TOUCH_DEVICE_HEIGHT),
681*bb4ee6a4SAndroid Build Coastguard Worker                     name.as_deref(),
682*bb4ee6a4SAndroid Build Coastguard Worker                     idx as u32,
683*bb4ee6a4SAndroid Build Coastguard Worker                 )?);
684*bb4ee6a4SAndroid Build Coastguard Worker             }
685*bb4ee6a4SAndroid Build Coastguard Worker             _ => {}
686*bb4ee6a4SAndroid Build Coastguard Worker         }
687*bb4ee6a4SAndroid Build Coastguard Worker     }
688*bb4ee6a4SAndroid Build Coastguard Worker     drop(multi_touch_pipes);
689*bb4ee6a4SAndroid Build Coastguard Worker 
690*bb4ee6a4SAndroid Build Coastguard Worker     product::push_mouse_device(cfg, &mut input_event_vmm_config, &mut devs)?;
691*bb4ee6a4SAndroid Build Coastguard Worker 
692*bb4ee6a4SAndroid Build Coastguard Worker     for (idx, pipe) in input_event_vmm_config.mouse_pipes.drain(..).enumerate() {
693*bb4ee6a4SAndroid Build Coastguard Worker         devs.push(create_mouse_device(cfg, pipe, idx as u32)?);
694*bb4ee6a4SAndroid Build Coastguard Worker     }
695*bb4ee6a4SAndroid Build Coastguard Worker 
696*bb4ee6a4SAndroid Build Coastguard Worker     let keyboard_pipe = input_event_vmm_config
697*bb4ee6a4SAndroid Build Coastguard Worker         .keyboard_pipes
698*bb4ee6a4SAndroid Build Coastguard Worker         .pop()
699*bb4ee6a4SAndroid Build Coastguard Worker         .expect("at least one keyboard should be in GPU VMM config");
700*bb4ee6a4SAndroid Build Coastguard Worker     let dev = virtio::input::new_keyboard(
701*bb4ee6a4SAndroid Build Coastguard Worker         /* idx= */ 0,
702*bb4ee6a4SAndroid Build Coastguard Worker         keyboard_pipe,
703*bb4ee6a4SAndroid Build Coastguard Worker         virtio::base_features(cfg.protection_type),
704*bb4ee6a4SAndroid Build Coastguard Worker     )
705*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(Exit::InputDeviceNew, "failed to set up input device")?;
706*bb4ee6a4SAndroid Build Coastguard Worker 
707*bb4ee6a4SAndroid Build Coastguard Worker     devs.push(VirtioDeviceStub {
708*bb4ee6a4SAndroid Build Coastguard Worker         dev: Box::new(dev),
709*bb4ee6a4SAndroid Build Coastguard Worker         jail: None,
710*bb4ee6a4SAndroid Build Coastguard Worker     });
711*bb4ee6a4SAndroid Build Coastguard Worker 
712*bb4ee6a4SAndroid Build Coastguard Worker     Ok(devs)
713*bb4ee6a4SAndroid Build Coastguard Worker }
714*bb4ee6a4SAndroid Build Coastguard Worker 
715*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
716*bb4ee6a4SAndroid Build Coastguard Worker fn create_virtio_gpu_device(
717*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &mut Config,
718*bb4ee6a4SAndroid Build Coastguard Worker     mut gpu_vmm_config: GpuVmmConfig,
719*bb4ee6a4SAndroid Build Coastguard Worker     event_devices: Option<Vec<EventDevice>>,
720*bb4ee6a4SAndroid Build Coastguard Worker     wndproc_thread: &mut Option<WindowProcedureThread>,
721*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(clippy::ptr_arg)] control_tubes: &mut Vec<TaggedControlTube>,
722*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult<VirtioDeviceStub> {
723*bb4ee6a4SAndroid Build Coastguard Worker     let resource_bridges = Vec::<Tube>::new();
724*bb4ee6a4SAndroid Build Coastguard Worker 
725*bb4ee6a4SAndroid Build Coastguard Worker     product::push_gpu_control_tubes(control_tubes, &mut gpu_vmm_config);
726*bb4ee6a4SAndroid Build Coastguard Worker 
727*bb4ee6a4SAndroid Build Coastguard Worker     // If the GPU backend is passed, start up the vhost-user worker in the main process.
728*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(backend_config) = cfg.gpu_backend_config.take() {
729*bb4ee6a4SAndroid Build Coastguard Worker         let event_devices = event_devices.ok_or_else(|| {
730*bb4ee6a4SAndroid Build Coastguard Worker             anyhow!("event devices are missing when creating virtio-gpu in the current process.")
731*bb4ee6a4SAndroid Build Coastguard Worker         })?;
732*bb4ee6a4SAndroid Build Coastguard Worker         let wndproc_thread = wndproc_thread
733*bb4ee6a4SAndroid Build Coastguard Worker             .take()
734*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| anyhow!("Window procedure thread is missing."))?;
735*bb4ee6a4SAndroid Build Coastguard Worker 
736*bb4ee6a4SAndroid Build Coastguard Worker         std::thread::spawn(move || {
737*bb4ee6a4SAndroid Build Coastguard Worker             run_gpu_device_worker(backend_config, event_devices, wndproc_thread)
738*bb4ee6a4SAndroid Build Coastguard Worker         });
739*bb4ee6a4SAndroid Build Coastguard Worker     }
740*bb4ee6a4SAndroid Build Coastguard Worker 
741*bb4ee6a4SAndroid Build Coastguard Worker     // The GPU is always vhost-user, even if running in the main process.
742*bb4ee6a4SAndroid Build Coastguard Worker     let gpu_device_tube = gpu_vmm_config
743*bb4ee6a4SAndroid Build Coastguard Worker         .main_vhost_user_tube
744*bb4ee6a4SAndroid Build Coastguard Worker         .take()
745*bb4ee6a4SAndroid Build Coastguard Worker         .expect("GPU VMM vhost-user tube should be set");
746*bb4ee6a4SAndroid Build Coastguard Worker     let connection = Connection::<FrontendReq>::from(gpu_device_tube);
747*bb4ee6a4SAndroid Build Coastguard Worker 
748*bb4ee6a4SAndroid Build Coastguard Worker     create_vhost_user_gpu_device(virtio::base_features(cfg.protection_type), connection)
749*bb4ee6a4SAndroid Build Coastguard Worker         .context("create vhost-user GPU device")
750*bb4ee6a4SAndroid Build Coastguard Worker }
751*bb4ee6a4SAndroid Build Coastguard Worker 
752*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "audio")]
753*bb4ee6a4SAndroid Build Coastguard Worker fn create_virtio_snd_device(
754*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &mut Config,
755*bb4ee6a4SAndroid Build Coastguard Worker     snd_split_config: &mut SndSplitConfig,
756*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(clippy::ptr_arg)] control_tubes: &mut Vec<TaggedControlTube>,
757*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult<VirtioDeviceStub> {
758*bb4ee6a4SAndroid Build Coastguard Worker     let snd_vmm_config = snd_split_config
759*bb4ee6a4SAndroid Build Coastguard Worker         .vmm_config
760*bb4ee6a4SAndroid Build Coastguard Worker         .as_mut()
761*bb4ee6a4SAndroid Build Coastguard Worker         .expect("snd_vmm_config must exist");
762*bb4ee6a4SAndroid Build Coastguard Worker     product::push_snd_control_tubes(control_tubes, snd_vmm_config);
763*bb4ee6a4SAndroid Build Coastguard Worker 
764*bb4ee6a4SAndroid Build Coastguard Worker     // If the SND backend is passed, start up the vhost-user worker in the main process.
765*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(backend_config) = snd_split_config.backend_config.take() {
766*bb4ee6a4SAndroid Build Coastguard Worker         std::thread::spawn(move || run_snd_device_worker(backend_config));
767*bb4ee6a4SAndroid Build Coastguard Worker     }
768*bb4ee6a4SAndroid Build Coastguard Worker 
769*bb4ee6a4SAndroid Build Coastguard Worker     // The SND is always vhost-user, even if running in the main process.
770*bb4ee6a4SAndroid Build Coastguard Worker     let snd_device_tube = snd_vmm_config
771*bb4ee6a4SAndroid Build Coastguard Worker         .main_vhost_user_tube
772*bb4ee6a4SAndroid Build Coastguard Worker         .take()
773*bb4ee6a4SAndroid Build Coastguard Worker         .expect("Snd VMM vhost-user tube should be set");
774*bb4ee6a4SAndroid Build Coastguard Worker     let connection = Connection::<FrontendReq>::from(snd_device_tube);
775*bb4ee6a4SAndroid Build Coastguard Worker 
776*bb4ee6a4SAndroid Build Coastguard Worker     create_vhost_user_snd_device(virtio::base_features(cfg.protection_type), connection)
777*bb4ee6a4SAndroid Build Coastguard Worker         .context("create vhost-user SND device")
778*bb4ee6a4SAndroid Build Coastguard Worker }
779*bb4ee6a4SAndroid Build Coastguard Worker 
780*bb4ee6a4SAndroid Build Coastguard Worker fn create_devices(
781*bb4ee6a4SAndroid Build Coastguard Worker     cfg: &mut Config,
782*bb4ee6a4SAndroid Build Coastguard Worker     mem: &GuestMemory,
783*bb4ee6a4SAndroid Build Coastguard Worker     exit_evt_wrtube: &SendTube,
784*bb4ee6a4SAndroid Build Coastguard Worker     irq_control_tubes: &mut Vec<Tube>,
785*bb4ee6a4SAndroid Build Coastguard Worker     vm_memory_control_tubes: &mut Vec<Tube>,
786*bb4ee6a4SAndroid Build Coastguard Worker     control_tubes: &mut Vec<TaggedControlTube>,
787*bb4ee6a4SAndroid Build Coastguard Worker     disk_device_tubes: &mut Vec<Tube>,
788*bb4ee6a4SAndroid Build Coastguard Worker     initial_audio_session_states: &mut Vec<InitialAudioSessionState>,
789*bb4ee6a4SAndroid Build Coastguard Worker     balloon_device_tube: Option<Tube>,
790*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")] pvclock_device_tube: Option<Tube>,
791*bb4ee6a4SAndroid Build Coastguard Worker     dynamic_mapping_device_tube: Option<Tube>,
792*bb4ee6a4SAndroid Build Coastguard Worker     inflate_tube: Option<Tube>,
793*bb4ee6a4SAndroid Build Coastguard Worker     init_balloon_size: u64,
794*bb4ee6a4SAndroid Build Coastguard Worker     tsc_frequency: u64,
795*bb4ee6a4SAndroid Build Coastguard Worker     virtio_snd_state_device_tube: Option<Tube>,
796*bb4ee6a4SAndroid Build Coastguard Worker     virtio_snd_control_device_tube: Option<Tube>,
797*bb4ee6a4SAndroid Build Coastguard Worker ) -> DeviceResult<Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>> {
798*bb4ee6a4SAndroid Build Coastguard Worker     let stubs = create_virtio_devices(
799*bb4ee6a4SAndroid Build Coastguard Worker         cfg,
800*bb4ee6a4SAndroid Build Coastguard Worker         exit_evt_wrtube,
801*bb4ee6a4SAndroid Build Coastguard Worker         control_tubes,
802*bb4ee6a4SAndroid Build Coastguard Worker         disk_device_tubes,
803*bb4ee6a4SAndroid Build Coastguard Worker         initial_audio_session_states,
804*bb4ee6a4SAndroid Build Coastguard Worker         balloon_device_tube,
805*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "pvclock")]
806*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device_tube,
807*bb4ee6a4SAndroid Build Coastguard Worker         dynamic_mapping_device_tube,
808*bb4ee6a4SAndroid Build Coastguard Worker         inflate_tube,
809*bb4ee6a4SAndroid Build Coastguard Worker         init_balloon_size,
810*bb4ee6a4SAndroid Build Coastguard Worker         tsc_frequency,
811*bb4ee6a4SAndroid Build Coastguard Worker         virtio_snd_state_device_tube,
812*bb4ee6a4SAndroid Build Coastguard Worker         virtio_snd_control_device_tube,
813*bb4ee6a4SAndroid Build Coastguard Worker     )?;
814*bb4ee6a4SAndroid Build Coastguard Worker 
815*bb4ee6a4SAndroid Build Coastguard Worker     let mut pci_devices = Vec::new();
816*bb4ee6a4SAndroid Build Coastguard Worker 
817*bb4ee6a4SAndroid Build Coastguard Worker     for stub in stubs {
818*bb4ee6a4SAndroid Build Coastguard Worker         let (msi_host_tube, msi_device_tube) =
819*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
820*bb4ee6a4SAndroid Build Coastguard Worker         irq_control_tubes.push(msi_host_tube);
821*bb4ee6a4SAndroid Build Coastguard Worker 
822*bb4ee6a4SAndroid Build Coastguard Worker         let shared_memory_tube = if stub.dev.get_shared_memory_region().is_some() {
823*bb4ee6a4SAndroid Build Coastguard Worker             let (host_tube, device_tube) =
824*bb4ee6a4SAndroid Build Coastguard Worker                 Tube::pair().context("failed to create VVU proxy tube")?;
825*bb4ee6a4SAndroid Build Coastguard Worker             vm_memory_control_tubes.push(host_tube);
826*bb4ee6a4SAndroid Build Coastguard Worker             Some(device_tube)
827*bb4ee6a4SAndroid Build Coastguard Worker         } else {
828*bb4ee6a4SAndroid Build Coastguard Worker             None
829*bb4ee6a4SAndroid Build Coastguard Worker         };
830*bb4ee6a4SAndroid Build Coastguard Worker 
831*bb4ee6a4SAndroid Build Coastguard Worker         let (ioevent_host_tube, ioevent_device_tube) =
832*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().context("failed to create ioevent tube")?;
833*bb4ee6a4SAndroid Build Coastguard Worker         vm_memory_control_tubes.push(ioevent_host_tube);
834*bb4ee6a4SAndroid Build Coastguard Worker 
835*bb4ee6a4SAndroid Build Coastguard Worker         let (vm_control_host_tube, vm_control_device_tube) =
836*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().context("failed to create vm_control tube")?;
837*bb4ee6a4SAndroid Build Coastguard Worker         control_tubes.push(TaggedControlTube::Vm(FlushOnDropTube::from(
838*bb4ee6a4SAndroid Build Coastguard Worker             vm_control_host_tube,
839*bb4ee6a4SAndroid Build Coastguard Worker         )));
840*bb4ee6a4SAndroid Build Coastguard Worker 
841*bb4ee6a4SAndroid Build Coastguard Worker         let dev = Box::new(
842*bb4ee6a4SAndroid Build Coastguard Worker             VirtioPciDevice::new(
843*bb4ee6a4SAndroid Build Coastguard Worker                 mem.clone(),
844*bb4ee6a4SAndroid Build Coastguard Worker                 stub.dev,
845*bb4ee6a4SAndroid Build Coastguard Worker                 msi_device_tube,
846*bb4ee6a4SAndroid Build Coastguard Worker                 cfg.disable_virtio_intx,
847*bb4ee6a4SAndroid Build Coastguard Worker                 shared_memory_tube.map(VmMemoryClient::new),
848*bb4ee6a4SAndroid Build Coastguard Worker                 VmMemoryClient::new(ioevent_device_tube),
849*bb4ee6a4SAndroid Build Coastguard Worker                 vm_control_device_tube,
850*bb4ee6a4SAndroid Build Coastguard Worker             )
851*bb4ee6a4SAndroid Build Coastguard Worker             .exit_context(Exit::VirtioPciDev, "failed to create virtio pci dev")?,
852*bb4ee6a4SAndroid Build Coastguard Worker         ) as Box<dyn BusDeviceObj>;
853*bb4ee6a4SAndroid Build Coastguard Worker         pci_devices.push((dev, stub.jail));
854*bb4ee6a4SAndroid Build Coastguard Worker     }
855*bb4ee6a4SAndroid Build Coastguard Worker 
856*bb4ee6a4SAndroid Build Coastguard Worker     Ok(pci_devices)
857*bb4ee6a4SAndroid Build Coastguard Worker }
858*bb4ee6a4SAndroid Build Coastguard Worker 
859*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
860*bb4ee6a4SAndroid Build Coastguard Worker struct PvClockError(String);
861*bb4ee6a4SAndroid Build Coastguard Worker 
862*bb4ee6a4SAndroid Build Coastguard Worker fn handle_readable_event<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
863*bb4ee6a4SAndroid Build Coastguard Worker     event: &TriggeredEvent<Token>,
864*bb4ee6a4SAndroid Build Coastguard Worker     vm_control_ids_to_remove: &mut Vec<usize>,
865*bb4ee6a4SAndroid Build Coastguard Worker     next_control_id: &mut usize,
866*bb4ee6a4SAndroid Build Coastguard Worker     service_vm_state: &mut ServiceVmState,
867*bb4ee6a4SAndroid Build Coastguard Worker     disk_host_tubes: &[Tube],
868*bb4ee6a4SAndroid Build Coastguard Worker     ipc_main_loop_tube: Option<&Tube>,
869*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gpu")] gpu_control_tube: Option<&Tube>,
870*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_rdtube: &RecvTube,
871*bb4ee6a4SAndroid Build Coastguard Worker     control_tubes: &mut BTreeMap<usize, TaggedControlTube>,
872*bb4ee6a4SAndroid Build Coastguard Worker     guest_os: &mut RunnableLinuxVm<V, Vcpu>,
873*bb4ee6a4SAndroid Build Coastguard Worker     sys_allocator_mutex: &Arc<Mutex<SystemAllocator>>,
874*bb4ee6a4SAndroid Build Coastguard Worker     virtio_snd_host_mute_tubes: &mut [Tube],
875*bb4ee6a4SAndroid Build Coastguard Worker     proto_main_loop_tube: Option<&ProtoTube>,
876*bb4ee6a4SAndroid Build Coastguard Worker     anti_tamper_main_thread_tube: &Option<ProtoTube>,
877*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "balloon")] mut balloon_tube: Option<&mut BalloonTube>,
878*bb4ee6a4SAndroid Build Coastguard Worker     memory_size_mb: u64,
879*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_boxes: &Mutex<Vec<Box<dyn VcpuArch>>>,
880*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")] pvclock_host_tube: &Option<Tube>,
881*bb4ee6a4SAndroid Build Coastguard Worker     run_mode_arc: &VcpuRunMode,
882*bb4ee6a4SAndroid Build Coastguard Worker     region_state: &mut VmMemoryRegionState,
883*bb4ee6a4SAndroid Build Coastguard Worker     vm_control_server: Option<&mut ControlServer>,
884*bb4ee6a4SAndroid Build Coastguard Worker     irq_handler_control: &Tube,
885*bb4ee6a4SAndroid Build Coastguard Worker     device_ctrl_tube: &Tube,
886*bb4ee6a4SAndroid Build Coastguard Worker     wait_ctx: &WaitContext<Token>,
887*bb4ee6a4SAndroid Build Coastguard Worker     force_s2idle: bool,
888*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_control_channels: &[mpsc::Sender<VcpuControl>],
889*bb4ee6a4SAndroid Build Coastguard Worker     suspended_pvclock_state: &mut Option<hypervisor::ClockState>,
890*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Option<ExitState>> {
891*bb4ee6a4SAndroid Build Coastguard Worker     let mut execute_vm_request = |request: VmRequest, guest_os: &mut RunnableLinuxVm<V, Vcpu>| {
892*bb4ee6a4SAndroid Build Coastguard Worker         if let VmRequest::Exit = request {
893*bb4ee6a4SAndroid Build Coastguard Worker             return (VmResponse::Ok, Some(VmRunMode::Exiting));
894*bb4ee6a4SAndroid Build Coastguard Worker         }
895*bb4ee6a4SAndroid Build Coastguard Worker         let vcpu_size = vcpu_boxes.lock().len();
896*bb4ee6a4SAndroid Build Coastguard Worker         let resp = request.execute(
897*bb4ee6a4SAndroid Build Coastguard Worker             &guest_os.vm,
898*bb4ee6a4SAndroid Build Coastguard Worker             disk_host_tubes,
899*bb4ee6a4SAndroid Build Coastguard Worker             &mut guest_os.pm,
900*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "gpu")]
901*bb4ee6a4SAndroid Build Coastguard Worker             gpu_control_tube,
902*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(not(feature = "gpu"))]
903*bb4ee6a4SAndroid Build Coastguard Worker             None,
904*bb4ee6a4SAndroid Build Coastguard Worker             None,
905*bb4ee6a4SAndroid Build Coastguard Worker             &mut None,
906*bb4ee6a4SAndroid Build Coastguard Worker             |msg| {
907*bb4ee6a4SAndroid Build Coastguard Worker                 kick_all_vcpus(
908*bb4ee6a4SAndroid Build Coastguard Worker                     run_mode_arc,
909*bb4ee6a4SAndroid Build Coastguard Worker                     vcpu_control_channels,
910*bb4ee6a4SAndroid Build Coastguard Worker                     vcpu_boxes,
911*bb4ee6a4SAndroid Build Coastguard Worker                     guest_os.irq_chip.as_ref(),
912*bb4ee6a4SAndroid Build Coastguard Worker                     #[cfg(feature = "pvclock")]
913*bb4ee6a4SAndroid Build Coastguard Worker                     pvclock_host_tube,
914*bb4ee6a4SAndroid Build Coastguard Worker                     &guest_os.resume_notify_devices,
915*bb4ee6a4SAndroid Build Coastguard Worker                     msg,
916*bb4ee6a4SAndroid Build Coastguard Worker                 );
917*bb4ee6a4SAndroid Build Coastguard Worker             },
918*bb4ee6a4SAndroid Build Coastguard Worker             force_s2idle,
919*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "swap")]
920*bb4ee6a4SAndroid Build Coastguard Worker             None,
921*bb4ee6a4SAndroid Build Coastguard Worker             device_ctrl_tube,
922*bb4ee6a4SAndroid Build Coastguard Worker             vcpu_size,
923*bb4ee6a4SAndroid Build Coastguard Worker             irq_handler_control,
924*bb4ee6a4SAndroid Build Coastguard Worker             || guest_os.irq_chip.as_ref().snapshot(vcpu_size),
925*bb4ee6a4SAndroid Build Coastguard Worker             suspended_pvclock_state,
926*bb4ee6a4SAndroid Build Coastguard Worker         );
927*bb4ee6a4SAndroid Build Coastguard Worker         (resp, None)
928*bb4ee6a4SAndroid Build Coastguard Worker     };
929*bb4ee6a4SAndroid Build Coastguard Worker 
930*bb4ee6a4SAndroid Build Coastguard Worker     match event.token {
931*bb4ee6a4SAndroid Build Coastguard Worker         Token::VmEvent => match vm_evt_rdtube.recv::<VmEventType>() {
932*bb4ee6a4SAndroid Build Coastguard Worker             Ok(vm_event) => {
933*bb4ee6a4SAndroid Build Coastguard Worker                 let exit_state = match vm_event {
934*bb4ee6a4SAndroid Build Coastguard Worker                     VmEventType::Exit => {
935*bb4ee6a4SAndroid Build Coastguard Worker                         info!("vcpu requested shutdown");
936*bb4ee6a4SAndroid Build Coastguard Worker                         Some(ExitState::Stop)
937*bb4ee6a4SAndroid Build Coastguard Worker                     }
938*bb4ee6a4SAndroid Build Coastguard Worker                     VmEventType::Reset => {
939*bb4ee6a4SAndroid Build Coastguard Worker                         info!("vcpu requested reset");
940*bb4ee6a4SAndroid Build Coastguard Worker                         Some(ExitState::Reset)
941*bb4ee6a4SAndroid Build Coastguard Worker                     }
942*bb4ee6a4SAndroid Build Coastguard Worker                     VmEventType::Crash => {
943*bb4ee6a4SAndroid Build Coastguard Worker                         info!("vcpu crashed");
944*bb4ee6a4SAndroid Build Coastguard Worker                         Some(ExitState::Crash)
945*bb4ee6a4SAndroid Build Coastguard Worker                     }
946*bb4ee6a4SAndroid Build Coastguard Worker                     VmEventType::Panic(_) => {
947*bb4ee6a4SAndroid Build Coastguard Worker                         error!("got pvpanic event. this event is not expected on Windows.");
948*bb4ee6a4SAndroid Build Coastguard Worker                         None
949*bb4ee6a4SAndroid Build Coastguard Worker                     }
950*bb4ee6a4SAndroid Build Coastguard Worker                     VmEventType::WatchdogReset => {
951*bb4ee6a4SAndroid Build Coastguard Worker                         info!("vcpu stall detected");
952*bb4ee6a4SAndroid Build Coastguard Worker                         Some(ExitState::WatchdogReset)
953*bb4ee6a4SAndroid Build Coastguard Worker                     }
954*bb4ee6a4SAndroid Build Coastguard Worker                 };
955*bb4ee6a4SAndroid Build Coastguard Worker                 return Ok(exit_state);
956*bb4ee6a4SAndroid Build Coastguard Worker             }
957*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
958*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("failed to recv VmEvent: {}", e);
959*bb4ee6a4SAndroid Build Coastguard Worker             }
960*bb4ee6a4SAndroid Build Coastguard Worker         },
961*bb4ee6a4SAndroid Build Coastguard Worker         Token::BrokerShutdown => {
962*bb4ee6a4SAndroid Build Coastguard Worker             info!("main loop got broker shutdown event");
963*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(Some(ExitState::Stop));
964*bb4ee6a4SAndroid Build Coastguard Worker         }
965*bb4ee6a4SAndroid Build Coastguard Worker         Token::VmControlServer => {
966*bb4ee6a4SAndroid Build Coastguard Worker             let server =
967*bb4ee6a4SAndroid Build Coastguard Worker                 vm_control_server.expect("control server must exist if this event triggers");
968*bb4ee6a4SAndroid Build Coastguard Worker             let client = server.accept();
969*bb4ee6a4SAndroid Build Coastguard Worker             let id = *next_control_id;
970*bb4ee6a4SAndroid Build Coastguard Worker             *next_control_id += 1;
971*bb4ee6a4SAndroid Build Coastguard Worker             wait_ctx
972*bb4ee6a4SAndroid Build Coastguard Worker                 .add(client.0.get_read_notifier(), Token::VmControl { id })
973*bb4ee6a4SAndroid Build Coastguard Worker                 .exit_context(
974*bb4ee6a4SAndroid Build Coastguard Worker                     Exit::WaitContextAdd,
975*bb4ee6a4SAndroid Build Coastguard Worker                     "failed to add trigger to wait context",
976*bb4ee6a4SAndroid Build Coastguard Worker                 )?;
977*bb4ee6a4SAndroid Build Coastguard Worker             wait_ctx
978*bb4ee6a4SAndroid Build Coastguard Worker                 .add(client.0.get_close_notifier(), Token::VmControl { id })
979*bb4ee6a4SAndroid Build Coastguard Worker                 .exit_context(
980*bb4ee6a4SAndroid Build Coastguard Worker                     Exit::WaitContextAdd,
981*bb4ee6a4SAndroid Build Coastguard Worker                     "failed to add trigger to wait context",
982*bb4ee6a4SAndroid Build Coastguard Worker                 )?;
983*bb4ee6a4SAndroid Build Coastguard Worker             control_tubes.insert(id, TaggedControlTube::Vm(client));
984*bb4ee6a4SAndroid Build Coastguard Worker         }
985*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(clippy::collapsible_match)]
986*bb4ee6a4SAndroid Build Coastguard Worker         Token::VmControl { id } => {
987*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(tube) = control_tubes.get(&id) {
988*bb4ee6a4SAndroid Build Coastguard Worker                 #[allow(clippy::single_match)]
989*bb4ee6a4SAndroid Build Coastguard Worker                 match tube {
990*bb4ee6a4SAndroid Build Coastguard Worker                     TaggedControlTube::Product(product_tube) => {
991*bb4ee6a4SAndroid Build Coastguard Worker                         product::handle_tagged_control_tube_event(
992*bb4ee6a4SAndroid Build Coastguard Worker                             product_tube,
993*bb4ee6a4SAndroid Build Coastguard Worker                             virtio_snd_host_mute_tubes,
994*bb4ee6a4SAndroid Build Coastguard Worker                             service_vm_state,
995*bb4ee6a4SAndroid Build Coastguard Worker                             ipc_main_loop_tube,
996*bb4ee6a4SAndroid Build Coastguard Worker                         )
997*bb4ee6a4SAndroid Build Coastguard Worker                     }
998*bb4ee6a4SAndroid Build Coastguard Worker                     TaggedControlTube::Vm(tube) => match tube.0.recv::<VmRequest>() {
999*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(request) => {
1000*bb4ee6a4SAndroid Build Coastguard Worker                             let mut run_mode_opt = None;
1001*bb4ee6a4SAndroid Build Coastguard Worker                             let response = match request {
1002*bb4ee6a4SAndroid Build Coastguard Worker                                 VmRequest::HotPlugVfioCommand { device, add } => {
1003*bb4ee6a4SAndroid Build Coastguard Worker                                     // Suppress warnings.
1004*bb4ee6a4SAndroid Build Coastguard Worker                                     let _ = (device, add);
1005*bb4ee6a4SAndroid Build Coastguard Worker                                     unimplemented!("not implemented on Windows");
1006*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1007*bb4ee6a4SAndroid Build Coastguard Worker                                 #[cfg(feature = "registered_events")]
1008*bb4ee6a4SAndroid Build Coastguard Worker                                 VmRequest::RegisterListener { socket_addr, event } => {
1009*bb4ee6a4SAndroid Build Coastguard Worker                                     unimplemented!("not implemented on Windows");
1010*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1011*bb4ee6a4SAndroid Build Coastguard Worker                                 #[cfg(feature = "registered_events")]
1012*bb4ee6a4SAndroid Build Coastguard Worker                                 VmRequest::UnregisterListener { socket_addr, event } => {
1013*bb4ee6a4SAndroid Build Coastguard Worker                                     unimplemented!("not implemented on Windows");
1014*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1015*bb4ee6a4SAndroid Build Coastguard Worker                                 #[cfg(feature = "registered_events")]
1016*bb4ee6a4SAndroid Build Coastguard Worker                                 VmRequest::Unregister { socket_addr } => {
1017*bb4ee6a4SAndroid Build Coastguard Worker                                     unimplemented!("not implemented on Windows");
1018*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1019*bb4ee6a4SAndroid Build Coastguard Worker                                 #[cfg(feature = "balloon")]
1020*bb4ee6a4SAndroid Build Coastguard Worker                                 VmRequest::BalloonCommand(cmd) => {
1021*bb4ee6a4SAndroid Build Coastguard Worker                                     if let Some(balloon_tube) = balloon_tube {
1022*bb4ee6a4SAndroid Build Coastguard Worker                                         if let Some((r, key)) = balloon_tube.send_cmd(cmd, Some(id))
1023*bb4ee6a4SAndroid Build Coastguard Worker                                         {
1024*bb4ee6a4SAndroid Build Coastguard Worker                                             if key != id {
1025*bb4ee6a4SAndroid Build Coastguard Worker                                                 unimplemented!("not implemented on Windows");
1026*bb4ee6a4SAndroid Build Coastguard Worker                                             }
1027*bb4ee6a4SAndroid Build Coastguard Worker                                             Some(r)
1028*bb4ee6a4SAndroid Build Coastguard Worker                                         } else {
1029*bb4ee6a4SAndroid Build Coastguard Worker                                             None
1030*bb4ee6a4SAndroid Build Coastguard Worker                                         }
1031*bb4ee6a4SAndroid Build Coastguard Worker                                     } else {
1032*bb4ee6a4SAndroid Build Coastguard Worker                                         error!("balloon not enabled");
1033*bb4ee6a4SAndroid Build Coastguard Worker                                         None
1034*bb4ee6a4SAndroid Build Coastguard Worker                                     }
1035*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1036*bb4ee6a4SAndroid Build Coastguard Worker                                 _ => {
1037*bb4ee6a4SAndroid Build Coastguard Worker                                     let (resp, run_mode_ret) =
1038*bb4ee6a4SAndroid Build Coastguard Worker                                         execute_vm_request(request, guest_os);
1039*bb4ee6a4SAndroid Build Coastguard Worker                                     run_mode_opt = run_mode_ret;
1040*bb4ee6a4SAndroid Build Coastguard Worker                                     Some(resp)
1041*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1042*bb4ee6a4SAndroid Build Coastguard Worker                             };
1043*bb4ee6a4SAndroid Build Coastguard Worker 
1044*bb4ee6a4SAndroid Build Coastguard Worker                             if let Some(response) = response {
1045*bb4ee6a4SAndroid Build Coastguard Worker                                 if let Err(e) = tube.0.send(&response) {
1046*bb4ee6a4SAndroid Build Coastguard Worker                                     error!("failed to send VmResponse: {}", e);
1047*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1048*bb4ee6a4SAndroid Build Coastguard Worker                             }
1049*bb4ee6a4SAndroid Build Coastguard Worker                             if let Some(exit_state) =
1050*bb4ee6a4SAndroid Build Coastguard Worker                                 handle_run_mode_change_for_vm_request(&run_mode_opt, guest_os)
1051*bb4ee6a4SAndroid Build Coastguard Worker                             {
1052*bb4ee6a4SAndroid Build Coastguard Worker                                 return Ok(Some(exit_state));
1053*bb4ee6a4SAndroid Build Coastguard Worker                             }
1054*bb4ee6a4SAndroid Build Coastguard Worker                         }
1055*bb4ee6a4SAndroid Build Coastguard Worker                         Err(e) => {
1056*bb4ee6a4SAndroid Build Coastguard Worker                             if let TubeError::Disconnected = e {
1057*bb4ee6a4SAndroid Build Coastguard Worker                                 vm_control_ids_to_remove.push(id);
1058*bb4ee6a4SAndroid Build Coastguard Worker                             } else {
1059*bb4ee6a4SAndroid Build Coastguard Worker                                 error!("failed to recv VmRequest: {}", e);
1060*bb4ee6a4SAndroid Build Coastguard Worker                             }
1061*bb4ee6a4SAndroid Build Coastguard Worker                         }
1062*bb4ee6a4SAndroid Build Coastguard Worker                     },
1063*bb4ee6a4SAndroid Build Coastguard Worker                 }
1064*bb4ee6a4SAndroid Build Coastguard Worker             }
1065*bb4ee6a4SAndroid Build Coastguard Worker         }
1066*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "balloon")]
1067*bb4ee6a4SAndroid Build Coastguard Worker         Token::BalloonTube => match balloon_tube.as_mut().expect("missing balloon tube").recv() {
1068*bb4ee6a4SAndroid Build Coastguard Worker             Ok(resp) => {
1069*bb4ee6a4SAndroid Build Coastguard Worker                 for (resp, idx) in resp {
1070*bb4ee6a4SAndroid Build Coastguard Worker                     if let Some(TaggedControlTube::Vm(tube)) = control_tubes.get(&idx) {
1071*bb4ee6a4SAndroid Build Coastguard Worker                         if let Err(e) = tube.0.send(&resp) {
1072*bb4ee6a4SAndroid Build Coastguard Worker                             error!("failed to send VmResponse: {}", e);
1073*bb4ee6a4SAndroid Build Coastguard Worker                         }
1074*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
1075*bb4ee6a4SAndroid Build Coastguard Worker                         error!("Bad tube index {}", idx);
1076*bb4ee6a4SAndroid Build Coastguard Worker                     }
1077*bb4ee6a4SAndroid Build Coastguard Worker                 }
1078*bb4ee6a4SAndroid Build Coastguard Worker             }
1079*bb4ee6a4SAndroid Build Coastguard Worker             Err(err) => {
1080*bb4ee6a4SAndroid Build Coastguard Worker                 error!("Error processing balloon tube {:?}", err)
1081*bb4ee6a4SAndroid Build Coastguard Worker             }
1082*bb4ee6a4SAndroid Build Coastguard Worker         },
1083*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(not(feature = "balloon"))]
1084*bb4ee6a4SAndroid Build Coastguard Worker         Token::BalloonTube => unreachable!("balloon tube not registered"),
1085*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(unreachable_patterns)]
1086*bb4ee6a4SAndroid Build Coastguard Worker         _ => {
1087*bb4ee6a4SAndroid Build Coastguard Worker             let run_mode_opt = product::handle_received_token(
1088*bb4ee6a4SAndroid Build Coastguard Worker                 &event.token,
1089*bb4ee6a4SAndroid Build Coastguard Worker                 anti_tamper_main_thread_tube,
1090*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "balloon")]
1091*bb4ee6a4SAndroid Build Coastguard Worker                 balloon_tube,
1092*bb4ee6a4SAndroid Build Coastguard Worker                 control_tubes,
1093*bb4ee6a4SAndroid Build Coastguard Worker                 guest_os,
1094*bb4ee6a4SAndroid Build Coastguard Worker                 ipc_main_loop_tube,
1095*bb4ee6a4SAndroid Build Coastguard Worker                 memory_size_mb,
1096*bb4ee6a4SAndroid Build Coastguard Worker                 proto_main_loop_tube,
1097*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "pvclock")]
1098*bb4ee6a4SAndroid Build Coastguard Worker                 pvclock_host_tube,
1099*bb4ee6a4SAndroid Build Coastguard Worker                 run_mode_arc,
1100*bb4ee6a4SAndroid Build Coastguard Worker                 service_vm_state,
1101*bb4ee6a4SAndroid Build Coastguard Worker                 vcpu_boxes,
1102*bb4ee6a4SAndroid Build Coastguard Worker                 virtio_snd_host_mute_tubes,
1103*bb4ee6a4SAndroid Build Coastguard Worker                 execute_vm_request,
1104*bb4ee6a4SAndroid Build Coastguard Worker             );
1105*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(exit_state) = handle_run_mode_change_for_vm_request(&run_mode_opt, guest_os)
1106*bb4ee6a4SAndroid Build Coastguard Worker             {
1107*bb4ee6a4SAndroid Build Coastguard Worker                 return Ok(Some(exit_state));
1108*bb4ee6a4SAndroid Build Coastguard Worker             }
1109*bb4ee6a4SAndroid Build Coastguard Worker         }
1110*bb4ee6a4SAndroid Build Coastguard Worker     };
1111*bb4ee6a4SAndroid Build Coastguard Worker     Ok(None)
1112*bb4ee6a4SAndroid Build Coastguard Worker }
1113*bb4ee6a4SAndroid Build Coastguard Worker 
1114*bb4ee6a4SAndroid Build Coastguard Worker /// Handles a run mode change (if one occurred) if one is pending as a
1115*bb4ee6a4SAndroid Build Coastguard Worker /// result a VmRequest. The parameter, run_mode_opt, is the run mode change
1116*bb4ee6a4SAndroid Build Coastguard Worker /// proposed by the VmRequest's execution.
1117*bb4ee6a4SAndroid Build Coastguard Worker ///
1118*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the exit state, if it changed due to a run mode change.
1119*bb4ee6a4SAndroid Build Coastguard Worker /// None otherwise.
1120*bb4ee6a4SAndroid Build Coastguard Worker fn handle_run_mode_change_for_vm_request<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
1121*bb4ee6a4SAndroid Build Coastguard Worker     run_mode_opt: &Option<VmRunMode>,
1122*bb4ee6a4SAndroid Build Coastguard Worker     guest_os: &mut RunnableLinuxVm<V, Vcpu>,
1123*bb4ee6a4SAndroid Build Coastguard Worker ) -> Option<ExitState> {
1124*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(run_mode) = run_mode_opt {
1125*bb4ee6a4SAndroid Build Coastguard Worker         info!("control socket changed run mode to {}", run_mode);
1126*bb4ee6a4SAndroid Build Coastguard Worker         match run_mode {
1127*bb4ee6a4SAndroid Build Coastguard Worker             VmRunMode::Exiting => return Some(ExitState::Stop),
1128*bb4ee6a4SAndroid Build Coastguard Worker             _ => unreachable!(),
1129*bb4ee6a4SAndroid Build Coastguard Worker         }
1130*bb4ee6a4SAndroid Build Coastguard Worker     }
1131*bb4ee6a4SAndroid Build Coastguard Worker     // No exit state change.
1132*bb4ee6a4SAndroid Build Coastguard Worker     None
1133*bb4ee6a4SAndroid Build Coastguard Worker }
1134*bb4ee6a4SAndroid Build Coastguard Worker 
1135*bb4ee6a4SAndroid Build Coastguard Worker /// Commands to control the VM Memory handler thread.
1136*bb4ee6a4SAndroid Build Coastguard Worker #[derive(serde::Serialize, serde::Deserialize)]
1137*bb4ee6a4SAndroid Build Coastguard Worker pub enum VmMemoryHandlerRequest {
1138*bb4ee6a4SAndroid Build Coastguard Worker     /// No response is sent for this command.
1139*bb4ee6a4SAndroid Build Coastguard Worker     Exit,
1140*bb4ee6a4SAndroid Build Coastguard Worker }
1141*bb4ee6a4SAndroid Build Coastguard Worker 
1142*bb4ee6a4SAndroid Build Coastguard Worker fn vm_memory_handler_thread(
1143*bb4ee6a4SAndroid Build Coastguard Worker     control_tubes: Vec<Tube>,
1144*bb4ee6a4SAndroid Build Coastguard Worker     mut vm: impl Vm,
1145*bb4ee6a4SAndroid Build Coastguard Worker     sys_allocator_mutex: Arc<Mutex<SystemAllocator>>,
1146*bb4ee6a4SAndroid Build Coastguard Worker     mut gralloc: RutabagaGralloc,
1147*bb4ee6a4SAndroid Build Coastguard Worker     handler_control: Tube,
1148*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
1149*bb4ee6a4SAndroid Build Coastguard Worker     #[derive(EventToken)]
1150*bb4ee6a4SAndroid Build Coastguard Worker     enum Token {
1151*bb4ee6a4SAndroid Build Coastguard Worker         VmControl { id: usize },
1152*bb4ee6a4SAndroid Build Coastguard Worker         HandlerControl,
1153*bb4ee6a4SAndroid Build Coastguard Worker     }
1154*bb4ee6a4SAndroid Build Coastguard Worker 
1155*bb4ee6a4SAndroid Build Coastguard Worker     let wait_ctx =
1156*bb4ee6a4SAndroid Build Coastguard Worker         WaitContext::build_with(&[(handler_control.get_read_notifier(), Token::HandlerControl)])
1157*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to build wait context")?;
1158*bb4ee6a4SAndroid Build Coastguard Worker     let mut control_tubes = BTreeMap::from_iter(control_tubes.into_iter().enumerate());
1159*bb4ee6a4SAndroid Build Coastguard Worker     for (id, socket) in control_tubes.iter() {
1160*bb4ee6a4SAndroid Build Coastguard Worker         wait_ctx
1161*bb4ee6a4SAndroid Build Coastguard Worker             .add(socket.get_read_notifier(), Token::VmControl { id: *id })
1162*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to add descriptor to wait context")?;
1163*bb4ee6a4SAndroid Build Coastguard Worker     }
1164*bb4ee6a4SAndroid Build Coastguard Worker 
1165*bb4ee6a4SAndroid Build Coastguard Worker     let mut region_state: VmMemoryRegionState = Default::default();
1166*bb4ee6a4SAndroid Build Coastguard Worker 
1167*bb4ee6a4SAndroid Build Coastguard Worker     'wait: loop {
1168*bb4ee6a4SAndroid Build Coastguard Worker         let events = {
1169*bb4ee6a4SAndroid Build Coastguard Worker             match wait_ctx.wait() {
1170*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(v) => v,
1171*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
1172*bb4ee6a4SAndroid Build Coastguard Worker                     error!("failed to poll: {}", e);
1173*bb4ee6a4SAndroid Build Coastguard Worker                     break;
1174*bb4ee6a4SAndroid Build Coastguard Worker                 }
1175*bb4ee6a4SAndroid Build Coastguard Worker             }
1176*bb4ee6a4SAndroid Build Coastguard Worker         };
1177*bb4ee6a4SAndroid Build Coastguard Worker 
1178*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm_control_ids_to_remove = Vec::new();
1179*bb4ee6a4SAndroid Build Coastguard Worker         for event in events.iter().filter(|e| e.is_readable) {
1180*bb4ee6a4SAndroid Build Coastguard Worker             match event.token {
1181*bb4ee6a4SAndroid Build Coastguard Worker                 Token::HandlerControl => match handler_control.recv::<VmMemoryHandlerRequest>() {
1182*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(request) => match request {
1183*bb4ee6a4SAndroid Build Coastguard Worker                         VmMemoryHandlerRequest::Exit => break 'wait,
1184*bb4ee6a4SAndroid Build Coastguard Worker                     },
1185*bb4ee6a4SAndroid Build Coastguard Worker                     Err(e) => {
1186*bb4ee6a4SAndroid Build Coastguard Worker                         if let TubeError::Disconnected = e {
1187*bb4ee6a4SAndroid Build Coastguard Worker                             panic!("vm memory control tube disconnected.");
1188*bb4ee6a4SAndroid Build Coastguard Worker                         } else {
1189*bb4ee6a4SAndroid Build Coastguard Worker                             error!("failed to recv VmMemoryHandlerRequest: {}", e);
1190*bb4ee6a4SAndroid Build Coastguard Worker                         }
1191*bb4ee6a4SAndroid Build Coastguard Worker                     }
1192*bb4ee6a4SAndroid Build Coastguard Worker                 },
1193*bb4ee6a4SAndroid Build Coastguard Worker 
1194*bb4ee6a4SAndroid Build Coastguard Worker                 Token::VmControl { id } => {
1195*bb4ee6a4SAndroid Build Coastguard Worker                     if let Some(tube) = control_tubes.get(&id) {
1196*bb4ee6a4SAndroid Build Coastguard Worker                         match tube.recv::<VmMemoryRequest>() {
1197*bb4ee6a4SAndroid Build Coastguard Worker                             Ok(request) => {
1198*bb4ee6a4SAndroid Build Coastguard Worker                                 let response = request.execute(
1199*bb4ee6a4SAndroid Build Coastguard Worker                                     &mut vm,
1200*bb4ee6a4SAndroid Build Coastguard Worker                                     &mut sys_allocator_mutex.lock(),
1201*bb4ee6a4SAndroid Build Coastguard Worker                                     &mut gralloc,
1202*bb4ee6a4SAndroid Build Coastguard Worker                                     None,
1203*bb4ee6a4SAndroid Build Coastguard Worker                                     &mut region_state,
1204*bb4ee6a4SAndroid Build Coastguard Worker                                 );
1205*bb4ee6a4SAndroid Build Coastguard Worker                                 if let Err(e) = tube.send(&response) {
1206*bb4ee6a4SAndroid Build Coastguard Worker                                     error!("failed to send VmMemoryControlResponse: {}", e);
1207*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1208*bb4ee6a4SAndroid Build Coastguard Worker                             }
1209*bb4ee6a4SAndroid Build Coastguard Worker                             Err(e) => {
1210*bb4ee6a4SAndroid Build Coastguard Worker                                 if let TubeError::Disconnected = e {
1211*bb4ee6a4SAndroid Build Coastguard Worker                                     vm_control_ids_to_remove.push(id);
1212*bb4ee6a4SAndroid Build Coastguard Worker                                 } else {
1213*bb4ee6a4SAndroid Build Coastguard Worker                                     error!("failed to recv VmMemoryControlRequest: {}", e);
1214*bb4ee6a4SAndroid Build Coastguard Worker                                 }
1215*bb4ee6a4SAndroid Build Coastguard Worker                             }
1216*bb4ee6a4SAndroid Build Coastguard Worker                         }
1217*bb4ee6a4SAndroid Build Coastguard Worker                     }
1218*bb4ee6a4SAndroid Build Coastguard Worker                 }
1219*bb4ee6a4SAndroid Build Coastguard Worker             }
1220*bb4ee6a4SAndroid Build Coastguard Worker         }
1221*bb4ee6a4SAndroid Build Coastguard Worker 
1222*bb4ee6a4SAndroid Build Coastguard Worker         remove_closed_tubes(&wait_ctx, &mut control_tubes, vm_control_ids_to_remove)?;
1223*bb4ee6a4SAndroid Build Coastguard Worker         if events
1224*bb4ee6a4SAndroid Build Coastguard Worker             .iter()
1225*bb4ee6a4SAndroid Build Coastguard Worker             .any(|e| e.is_hungup && !e.is_readable && matches!(e.token, Token::HandlerControl))
1226*bb4ee6a4SAndroid Build Coastguard Worker         {
1227*bb4ee6a4SAndroid Build Coastguard Worker             error!("vm memory handler control hung up but did not request an exit.");
1228*bb4ee6a4SAndroid Build Coastguard Worker             break 'wait;
1229*bb4ee6a4SAndroid Build Coastguard Worker         }
1230*bb4ee6a4SAndroid Build Coastguard Worker     }
1231*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
1232*bb4ee6a4SAndroid Build Coastguard Worker }
1233*bb4ee6a4SAndroid Build Coastguard Worker 
1234*bb4ee6a4SAndroid Build Coastguard Worker fn create_control_server(
1235*bb4ee6a4SAndroid Build Coastguard Worker     control_server_path: Option<PathBuf>,
1236*bb4ee6a4SAndroid Build Coastguard Worker     wait_ctx: &WaitContext<Token>,
1237*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Option<ControlServer>> {
1238*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(not(feature = "prod-build"))]
1239*bb4ee6a4SAndroid Build Coastguard Worker     {
1240*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(path) = control_server_path {
1241*bb4ee6a4SAndroid Build Coastguard Worker             let server =
1242*bb4ee6a4SAndroid Build Coastguard Worker                 ControlServer::new(path.to_str().expect("control socket path must be a string"))
1243*bb4ee6a4SAndroid Build Coastguard Worker                     .exit_context(
1244*bb4ee6a4SAndroid Build Coastguard Worker                         Exit::FailedToCreateControlServer,
1245*bb4ee6a4SAndroid Build Coastguard Worker                         "failed to create control server",
1246*bb4ee6a4SAndroid Build Coastguard Worker                     )?;
1247*bb4ee6a4SAndroid Build Coastguard Worker             wait_ctx
1248*bb4ee6a4SAndroid Build Coastguard Worker                 .add(server.client_waiting(), Token::VmControlServer)
1249*bb4ee6a4SAndroid Build Coastguard Worker                 .exit_context(
1250*bb4ee6a4SAndroid Build Coastguard Worker                     Exit::WaitContextAdd,
1251*bb4ee6a4SAndroid Build Coastguard Worker                     "failed to add control server to wait context",
1252*bb4ee6a4SAndroid Build Coastguard Worker                 )?;
1253*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(Some(server));
1254*bb4ee6a4SAndroid Build Coastguard Worker         }
1255*bb4ee6a4SAndroid Build Coastguard Worker     }
1256*bb4ee6a4SAndroid Build Coastguard Worker     Ok::<Option<ControlServer>, anyhow::Error>(None)
1257*bb4ee6a4SAndroid Build Coastguard Worker }
1258*bb4ee6a4SAndroid Build Coastguard Worker 
1259*bb4ee6a4SAndroid Build Coastguard Worker fn run_control<V: VmArch + 'static, Vcpu: VcpuArch + 'static>(
1260*bb4ee6a4SAndroid Build Coastguard Worker     mut guest_os: RunnableLinuxVm<V, Vcpu>,
1261*bb4ee6a4SAndroid Build Coastguard Worker     sys_allocator: SystemAllocator,
1262*bb4ee6a4SAndroid Build Coastguard Worker     control_tubes: Vec<TaggedControlTube>,
1263*bb4ee6a4SAndroid Build Coastguard Worker     irq_control_tubes: Vec<Tube>,
1264*bb4ee6a4SAndroid Build Coastguard Worker     vm_memory_control_tubes: Vec<Tube>,
1265*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_rdtube: RecvTube,
1266*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_wrtube: SendTube,
1267*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gpu")] gpu_control_tube: Option<Tube>,
1268*bb4ee6a4SAndroid Build Coastguard Worker     broker_shutdown_evt: Option<Event>,
1269*bb4ee6a4SAndroid Build Coastguard Worker     balloon_host_tube: Option<Tube>,
1270*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")] pvclock_host_tube: Option<Tube>,
1271*bb4ee6a4SAndroid Build Coastguard Worker     disk_host_tubes: Vec<Tube>,
1272*bb4ee6a4SAndroid Build Coastguard Worker     initial_audio_session_states: Vec<InitialAudioSessionState>,
1273*bb4ee6a4SAndroid Build Coastguard Worker     gralloc: RutabagaGralloc,
1274*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "stats")] stats: Option<Arc<Mutex<StatisticsCollector>>>,
1275*bb4ee6a4SAndroid Build Coastguard Worker     service_pipe_name: Option<String>,
1276*bb4ee6a4SAndroid Build Coastguard Worker     memory_size_mb: u64,
1277*bb4ee6a4SAndroid Build Coastguard Worker     host_cpu_topology: bool,
1278*bb4ee6a4SAndroid Build Coastguard Worker     tsc_sync_mitigations: TscSyncMitigations,
1279*bb4ee6a4SAndroid Build Coastguard Worker     force_calibrated_tsc_leaf: bool,
1280*bb4ee6a4SAndroid Build Coastguard Worker     mut product_args: RunControlArgs,
1281*bb4ee6a4SAndroid Build Coastguard Worker     mut virtio_snd_host_mute_tubes: Vec<Tube>,
1282*bb4ee6a4SAndroid Build Coastguard Worker     restore_path: Option<PathBuf>,
1283*bb4ee6a4SAndroid Build Coastguard Worker     control_server_path: Option<PathBuf>,
1284*bb4ee6a4SAndroid Build Coastguard Worker     force_s2idle: bool,
1285*bb4ee6a4SAndroid Build Coastguard Worker     suspended: bool,
1286*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<ExitState> {
1287*bb4ee6a4SAndroid Build Coastguard Worker     let (ipc_main_loop_tube, proto_main_loop_tube, _service_ipc) =
1288*bb4ee6a4SAndroid Build Coastguard Worker         start_service_ipc_listener(service_pipe_name)?;
1289*bb4ee6a4SAndroid Build Coastguard Worker 
1290*bb4ee6a4SAndroid Build Coastguard Worker     let mut service_vm_state = product::create_service_vm_state(memory_size_mb);
1291*bb4ee6a4SAndroid Build Coastguard Worker 
1292*bb4ee6a4SAndroid Build Coastguard Worker     let service_audio_states = product::create_service_audio_states_and_send_to_service(
1293*bb4ee6a4SAndroid Build Coastguard Worker         initial_audio_session_states,
1294*bb4ee6a4SAndroid Build Coastguard Worker         &ipc_main_loop_tube,
1295*bb4ee6a4SAndroid Build Coastguard Worker     )?;
1296*bb4ee6a4SAndroid Build Coastguard Worker 
1297*bb4ee6a4SAndroid Build Coastguard Worker     let sys_allocator_mutex = Arc::new(Mutex::new(sys_allocator));
1298*bb4ee6a4SAndroid Build Coastguard Worker 
1299*bb4ee6a4SAndroid Build Coastguard Worker     let exit_evt = Event::new().exit_context(Exit::CreateEvent, "failed to create event")?;
1300*bb4ee6a4SAndroid Build Coastguard Worker     let (irq_handler_control, irq_handler_control_for_worker) = Tube::pair().exit_context(
1301*bb4ee6a4SAndroid Build Coastguard Worker         Exit::CreateTube,
1302*bb4ee6a4SAndroid Build Coastguard Worker         "failed to create IRQ handler control Tube",
1303*bb4ee6a4SAndroid Build Coastguard Worker     )?;
1304*bb4ee6a4SAndroid Build Coastguard Worker 
1305*bb4ee6a4SAndroid Build Coastguard Worker     // Create a separate thread to wait on IRQ events. This is a natural division
1306*bb4ee6a4SAndroid Build Coastguard Worker     // because IRQ interrupts have no dependencies on other events, and this lets
1307*bb4ee6a4SAndroid Build Coastguard Worker     // us avoid approaching the Windows WaitForMultipleObjects 64-object limit.
1308*bb4ee6a4SAndroid Build Coastguard Worker     let irq_join_handle = IrqWaitWorker::start(
1309*bb4ee6a4SAndroid Build Coastguard Worker         irq_handler_control_for_worker,
1310*bb4ee6a4SAndroid Build Coastguard Worker         guest_os
1311*bb4ee6a4SAndroid Build Coastguard Worker             .irq_chip
1312*bb4ee6a4SAndroid Build Coastguard Worker             .try_box_clone()
1313*bb4ee6a4SAndroid Build Coastguard Worker             .exit_context(Exit::CloneEvent, "failed to clone irq chip")?,
1314*bb4ee6a4SAndroid Build Coastguard Worker         irq_control_tubes,
1315*bb4ee6a4SAndroid Build Coastguard Worker         sys_allocator_mutex.clone(),
1316*bb4ee6a4SAndroid Build Coastguard Worker     );
1317*bb4ee6a4SAndroid Build Coastguard Worker 
1318*bb4ee6a4SAndroid Build Coastguard Worker     let mut triggers = vec![(vm_evt_rdtube.get_read_notifier(), Token::VmEvent)];
1319*bb4ee6a4SAndroid Build Coastguard Worker     product::push_triggers(&mut triggers, &ipc_main_loop_tube, &proto_main_loop_tube);
1320*bb4ee6a4SAndroid Build Coastguard Worker     let wait_ctx = WaitContext::build_with(&triggers).exit_context(
1321*bb4ee6a4SAndroid Build Coastguard Worker         Exit::WaitContextAdd,
1322*bb4ee6a4SAndroid Build Coastguard Worker         "failed to add trigger to wait context",
1323*bb4ee6a4SAndroid Build Coastguard Worker     )?;
1324*bb4ee6a4SAndroid Build Coastguard Worker 
1325*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "balloon")]
1326*bb4ee6a4SAndroid Build Coastguard Worker     let mut balloon_tube = balloon_host_tube
1327*bb4ee6a4SAndroid Build Coastguard Worker         .map(|tube| -> Result<BalloonTube> {
1328*bb4ee6a4SAndroid Build Coastguard Worker             wait_ctx
1329*bb4ee6a4SAndroid Build Coastguard Worker                 .add(tube.get_read_notifier(), Token::BalloonTube)
1330*bb4ee6a4SAndroid Build Coastguard Worker                 .context("failed to add trigger to wait context")?;
1331*bb4ee6a4SAndroid Build Coastguard Worker             Ok(BalloonTube::new(tube))
1332*bb4ee6a4SAndroid Build Coastguard Worker         })
1333*bb4ee6a4SAndroid Build Coastguard Worker         .transpose()
1334*bb4ee6a4SAndroid Build Coastguard Worker         .context("failed to create balloon tube")?;
1335*bb4ee6a4SAndroid Build Coastguard Worker 
1336*bb4ee6a4SAndroid Build Coastguard Worker     let (vm_memory_handler_control, vm_memory_handler_control_for_thread) = Tube::pair()?;
1337*bb4ee6a4SAndroid Build Coastguard Worker     let vm_memory_handler_thread_join_handle = std::thread::Builder::new()
1338*bb4ee6a4SAndroid Build Coastguard Worker         .name("vm_memory_handler_thread".into())
1339*bb4ee6a4SAndroid Build Coastguard Worker         .spawn({
1340*bb4ee6a4SAndroid Build Coastguard Worker             let vm = guest_os.vm.try_clone().context("failed to clone Vm")?;
1341*bb4ee6a4SAndroid Build Coastguard Worker             let sys_allocator_mutex = sys_allocator_mutex.clone();
1342*bb4ee6a4SAndroid Build Coastguard Worker             move || {
1343*bb4ee6a4SAndroid Build Coastguard Worker                 vm_memory_handler_thread(
1344*bb4ee6a4SAndroid Build Coastguard Worker                     vm_memory_control_tubes,
1345*bb4ee6a4SAndroid Build Coastguard Worker                     vm,
1346*bb4ee6a4SAndroid Build Coastguard Worker                     sys_allocator_mutex,
1347*bb4ee6a4SAndroid Build Coastguard Worker                     gralloc,
1348*bb4ee6a4SAndroid Build Coastguard Worker                     vm_memory_handler_control_for_thread,
1349*bb4ee6a4SAndroid Build Coastguard Worker                 )
1350*bb4ee6a4SAndroid Build Coastguard Worker             }
1351*bb4ee6a4SAndroid Build Coastguard Worker         })
1352*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
1353*bb4ee6a4SAndroid Build Coastguard Worker 
1354*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(evt) = broker_shutdown_evt.as_ref() {
1355*bb4ee6a4SAndroid Build Coastguard Worker         wait_ctx.add(evt, Token::BrokerShutdown).exit_context(
1356*bb4ee6a4SAndroid Build Coastguard Worker             Exit::WaitContextAdd,
1357*bb4ee6a4SAndroid Build Coastguard Worker             "failed to add trigger to wait context",
1358*bb4ee6a4SAndroid Build Coastguard Worker         )?;
1359*bb4ee6a4SAndroid Build Coastguard Worker     }
1360*bb4ee6a4SAndroid Build Coastguard Worker 
1361*bb4ee6a4SAndroid Build Coastguard Worker     let mut control_tubes = BTreeMap::from_iter(control_tubes.into_iter().enumerate());
1362*bb4ee6a4SAndroid Build Coastguard Worker     let mut next_control_id = control_tubes.len();
1363*bb4ee6a4SAndroid Build Coastguard Worker     for (id, control_tube) in control_tubes.iter() {
1364*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(clippy::single_match)]
1365*bb4ee6a4SAndroid Build Coastguard Worker         match control_tube {
1366*bb4ee6a4SAndroid Build Coastguard Worker             TaggedControlTube::Product(product_tube) => wait_ctx
1367*bb4ee6a4SAndroid Build Coastguard Worker                 .add(
1368*bb4ee6a4SAndroid Build Coastguard Worker                     product_tube.get_read_notifier(),
1369*bb4ee6a4SAndroid Build Coastguard Worker                     Token::VmControl { id: *id },
1370*bb4ee6a4SAndroid Build Coastguard Worker                 )
1371*bb4ee6a4SAndroid Build Coastguard Worker                 .exit_context(
1372*bb4ee6a4SAndroid Build Coastguard Worker                     Exit::WaitContextAdd,
1373*bb4ee6a4SAndroid Build Coastguard Worker                     "failed to add trigger to wait context",
1374*bb4ee6a4SAndroid Build Coastguard Worker                 )?,
1375*bb4ee6a4SAndroid Build Coastguard Worker             _ => (),
1376*bb4ee6a4SAndroid Build Coastguard Worker         }
1377*bb4ee6a4SAndroid Build Coastguard Worker     }
1378*bb4ee6a4SAndroid Build Coastguard Worker 
1379*bb4ee6a4SAndroid Build Coastguard Worker     let (device_ctrl_tube, device_ctrl_resp) = Tube::pair().context("failed to create tube")?;
1380*bb4ee6a4SAndroid Build Coastguard Worker     guest_os.devices_thread = match create_devices_worker_thread(
1381*bb4ee6a4SAndroid Build Coastguard Worker         guest_os.vm.get_memory().clone(),
1382*bb4ee6a4SAndroid Build Coastguard Worker         guest_os.io_bus.clone(),
1383*bb4ee6a4SAndroid Build Coastguard Worker         guest_os.mmio_bus.clone(),
1384*bb4ee6a4SAndroid Build Coastguard Worker         device_ctrl_resp,
1385*bb4ee6a4SAndroid Build Coastguard Worker     ) {
1386*bb4ee6a4SAndroid Build Coastguard Worker         Ok(join_handle) => Some(join_handle),
1387*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
1388*bb4ee6a4SAndroid Build Coastguard Worker             return Err(anyhow!("Failed to start devices thread: {}", e));
1389*bb4ee6a4SAndroid Build Coastguard Worker         }
1390*bb4ee6a4SAndroid Build Coastguard Worker     };
1391*bb4ee6a4SAndroid Build Coastguard Worker 
1392*bb4ee6a4SAndroid Build Coastguard Worker     let vcpus: Vec<Option<_>> = match guest_os.vcpus.take() {
1393*bb4ee6a4SAndroid Build Coastguard Worker         Some(vec) => vec.into_iter().map(|vcpu| Some(vcpu)).collect(),
1394*bb4ee6a4SAndroid Build Coastguard Worker         None => iter::repeat_with(|| None)
1395*bb4ee6a4SAndroid Build Coastguard Worker             .take(guest_os.vcpu_count)
1396*bb4ee6a4SAndroid Build Coastguard Worker             .collect(),
1397*bb4ee6a4SAndroid Build Coastguard Worker     };
1398*bb4ee6a4SAndroid Build Coastguard Worker 
1399*bb4ee6a4SAndroid Build Coastguard Worker     let anti_tamper_main_thread_tube = spawn_anti_tamper_thread(&wait_ctx);
1400*bb4ee6a4SAndroid Build Coastguard Worker 
1401*bb4ee6a4SAndroid Build Coastguard Worker     let mut vm_control_server = create_control_server(control_server_path, &wait_ctx)?;
1402*bb4ee6a4SAndroid Build Coastguard Worker 
1403*bb4ee6a4SAndroid Build Coastguard Worker     let ime_thread = run_ime_thread(&mut product_args, &exit_evt)?;
1404*bb4ee6a4SAndroid Build Coastguard Worker 
1405*bb4ee6a4SAndroid Build Coastguard Worker     let original_terminal_mode = stdin().set_raw_mode().ok();
1406*bb4ee6a4SAndroid Build Coastguard Worker 
1407*bb4ee6a4SAndroid Build Coastguard Worker     let vcpu_boxes: Arc<Mutex<Vec<Box<dyn VcpuArch>>>> = Arc::new(Mutex::new(Vec::new()));
1408*bb4ee6a4SAndroid Build Coastguard Worker     let run_mode_arc = Arc::new(VcpuRunMode::default());
1409*bb4ee6a4SAndroid Build Coastguard Worker 
1410*bb4ee6a4SAndroid Build Coastguard Worker     let run_mode_state = if suspended {
1411*bb4ee6a4SAndroid Build Coastguard Worker         // Sleep devices before creating vcpus.
1412*bb4ee6a4SAndroid Build Coastguard Worker         device_ctrl_tube
1413*bb4ee6a4SAndroid Build Coastguard Worker             .send(&DeviceControlCommand::SleepDevices)
1414*bb4ee6a4SAndroid Build Coastguard Worker             .context("send command to devices control socket")?;
1415*bb4ee6a4SAndroid Build Coastguard Worker         match device_ctrl_tube
1416*bb4ee6a4SAndroid Build Coastguard Worker             .recv()
1417*bb4ee6a4SAndroid Build Coastguard Worker             .context("receive from devices control socket")?
1418*bb4ee6a4SAndroid Build Coastguard Worker         {
1419*bb4ee6a4SAndroid Build Coastguard Worker             VmResponse::Ok => (),
1420*bb4ee6a4SAndroid Build Coastguard Worker             resp => bail!("device sleep failed: {}", resp),
1421*bb4ee6a4SAndroid Build Coastguard Worker         }
1422*bb4ee6a4SAndroid Build Coastguard Worker         run_mode_arc.set_and_notify(VmRunMode::Suspending);
1423*bb4ee6a4SAndroid Build Coastguard Worker         VmRunMode::Suspending
1424*bb4ee6a4SAndroid Build Coastguard Worker     } else {
1425*bb4ee6a4SAndroid Build Coastguard Worker         VmRunMode::Running
1426*bb4ee6a4SAndroid Build Coastguard Worker     };
1427*bb4ee6a4SAndroid Build Coastguard Worker 
1428*bb4ee6a4SAndroid Build Coastguard Worker     // If we are restoring from a snapshot, then start suspended.
1429*bb4ee6a4SAndroid Build Coastguard Worker     if restore_path.is_some() {
1430*bb4ee6a4SAndroid Build Coastguard Worker         run_mode_arc.set_and_notify(VmRunMode::Suspending);
1431*bb4ee6a4SAndroid Build Coastguard Worker     }
1432*bb4ee6a4SAndroid Build Coastguard Worker 
1433*bb4ee6a4SAndroid Build Coastguard Worker     let (vcpu_threads, vcpu_control_channels) = run_all_vcpus(
1434*bb4ee6a4SAndroid Build Coastguard Worker         vcpus,
1435*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_boxes.clone(),
1436*bb4ee6a4SAndroid Build Coastguard Worker         &guest_os,
1437*bb4ee6a4SAndroid Build Coastguard Worker         &exit_evt,
1438*bb4ee6a4SAndroid Build Coastguard Worker         &vm_evt_wrtube,
1439*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "stats")]
1440*bb4ee6a4SAndroid Build Coastguard Worker         &stats,
1441*bb4ee6a4SAndroid Build Coastguard Worker         host_cpu_topology,
1442*bb4ee6a4SAndroid Build Coastguard Worker         run_mode_arc.clone(),
1443*bb4ee6a4SAndroid Build Coastguard Worker         tsc_sync_mitigations,
1444*bb4ee6a4SAndroid Build Coastguard Worker         force_calibrated_tsc_leaf,
1445*bb4ee6a4SAndroid Build Coastguard Worker     )?;
1446*bb4ee6a4SAndroid Build Coastguard Worker 
1447*bb4ee6a4SAndroid Build Coastguard Worker     // See comment on `VmRequest::execute`.
1448*bb4ee6a4SAndroid Build Coastguard Worker     let mut suspended_pvclock_state: Option<hypervisor::ClockState> = None;
1449*bb4ee6a4SAndroid Build Coastguard Worker 
1450*bb4ee6a4SAndroid Build Coastguard Worker     // Restore VM (if applicable).
1451*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(path) = restore_path {
1452*bb4ee6a4SAndroid Build Coastguard Worker         vm_control::do_restore(
1453*bb4ee6a4SAndroid Build Coastguard Worker             &path,
1454*bb4ee6a4SAndroid Build Coastguard Worker             |msg| {
1455*bb4ee6a4SAndroid Build Coastguard Worker                 kick_all_vcpus(
1456*bb4ee6a4SAndroid Build Coastguard Worker                     run_mode_arc.as_ref(),
1457*bb4ee6a4SAndroid Build Coastguard Worker                     &vcpu_control_channels,
1458*bb4ee6a4SAndroid Build Coastguard Worker                     vcpu_boxes.as_ref(),
1459*bb4ee6a4SAndroid Build Coastguard Worker                     guest_os.irq_chip.as_ref(),
1460*bb4ee6a4SAndroid Build Coastguard Worker                     #[cfg(feature = "pvclock")]
1461*bb4ee6a4SAndroid Build Coastguard Worker                     &pvclock_host_tube,
1462*bb4ee6a4SAndroid Build Coastguard Worker                     &guest_os.resume_notify_devices,
1463*bb4ee6a4SAndroid Build Coastguard Worker                     msg,
1464*bb4ee6a4SAndroid Build Coastguard Worker                 )
1465*bb4ee6a4SAndroid Build Coastguard Worker             },
1466*bb4ee6a4SAndroid Build Coastguard Worker             |msg, index| {
1467*bb4ee6a4SAndroid Build Coastguard Worker                 kick_vcpu(
1468*bb4ee6a4SAndroid Build Coastguard Worker                     run_mode_arc.as_ref(),
1469*bb4ee6a4SAndroid Build Coastguard Worker                     &vcpu_control_channels,
1470*bb4ee6a4SAndroid Build Coastguard Worker                     vcpu_boxes.as_ref(),
1471*bb4ee6a4SAndroid Build Coastguard Worker                     guest_os.irq_chip.as_ref(),
1472*bb4ee6a4SAndroid Build Coastguard Worker                     index,
1473*bb4ee6a4SAndroid Build Coastguard Worker                     msg,
1474*bb4ee6a4SAndroid Build Coastguard Worker                 )
1475*bb4ee6a4SAndroid Build Coastguard Worker             },
1476*bb4ee6a4SAndroid Build Coastguard Worker             &irq_handler_control,
1477*bb4ee6a4SAndroid Build Coastguard Worker             &device_ctrl_tube,
1478*bb4ee6a4SAndroid Build Coastguard Worker             guest_os.vcpu_count,
1479*bb4ee6a4SAndroid Build Coastguard Worker             |image| {
1480*bb4ee6a4SAndroid Build Coastguard Worker                 guest_os
1481*bb4ee6a4SAndroid Build Coastguard Worker                     .irq_chip
1482*bb4ee6a4SAndroid Build Coastguard Worker                     .try_box_clone()?
1483*bb4ee6a4SAndroid Build Coastguard Worker                     .restore(image, guest_os.vcpu_count)
1484*bb4ee6a4SAndroid Build Coastguard Worker             },
1485*bb4ee6a4SAndroid Build Coastguard Worker             /* require_encrypted= */ false,
1486*bb4ee6a4SAndroid Build Coastguard Worker             &mut suspended_pvclock_state,
1487*bb4ee6a4SAndroid Build Coastguard Worker         )?;
1488*bb4ee6a4SAndroid Build Coastguard Worker         // Allow the vCPUs to start for real.
1489*bb4ee6a4SAndroid Build Coastguard Worker         kick_all_vcpus(
1490*bb4ee6a4SAndroid Build Coastguard Worker             run_mode_arc.as_ref(),
1491*bb4ee6a4SAndroid Build Coastguard Worker             &vcpu_control_channels,
1492*bb4ee6a4SAndroid Build Coastguard Worker             vcpu_boxes.as_ref(),
1493*bb4ee6a4SAndroid Build Coastguard Worker             guest_os.irq_chip.as_ref(),
1494*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "pvclock")]
1495*bb4ee6a4SAndroid Build Coastguard Worker             &pvclock_host_tube,
1496*bb4ee6a4SAndroid Build Coastguard Worker             &guest_os.resume_notify_devices,
1497*bb4ee6a4SAndroid Build Coastguard Worker             // Other platforms (unix) have multiple modes they could start in (e.g. starting for
1498*bb4ee6a4SAndroid Build Coastguard Worker             // guest kernel debugging, etc). If/when we support those modes on Windows, we'll need
1499*bb4ee6a4SAndroid Build Coastguard Worker             // to enter that mode here rather than VmRunMode::Running.
1500*bb4ee6a4SAndroid Build Coastguard Worker             VcpuControl::RunState(run_mode_state),
1501*bb4ee6a4SAndroid Build Coastguard Worker         );
1502*bb4ee6a4SAndroid Build Coastguard Worker     }
1503*bb4ee6a4SAndroid Build Coastguard Worker 
1504*bb4ee6a4SAndroid Build Coastguard Worker     let mut exit_state = ExitState::Stop;
1505*bb4ee6a4SAndroid Build Coastguard Worker     let mut region_state: VmMemoryRegionState = Default::default();
1506*bb4ee6a4SAndroid Build Coastguard Worker 
1507*bb4ee6a4SAndroid Build Coastguard Worker     'poll: loop {
1508*bb4ee6a4SAndroid Build Coastguard Worker         let events = {
1509*bb4ee6a4SAndroid Build Coastguard Worker             match wait_ctx.wait() {
1510*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(v) => v,
1511*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
1512*bb4ee6a4SAndroid Build Coastguard Worker                     error!("failed to wait: {}", e);
1513*bb4ee6a4SAndroid Build Coastguard Worker                     break;
1514*bb4ee6a4SAndroid Build Coastguard Worker                 }
1515*bb4ee6a4SAndroid Build Coastguard Worker             }
1516*bb4ee6a4SAndroid Build Coastguard Worker         };
1517*bb4ee6a4SAndroid Build Coastguard Worker 
1518*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm_control_ids_to_remove = Vec::new();
1519*bb4ee6a4SAndroid Build Coastguard Worker         for event in events.iter().filter(|e| e.is_readable) {
1520*bb4ee6a4SAndroid Build Coastguard Worker             let state = handle_readable_event(
1521*bb4ee6a4SAndroid Build Coastguard Worker                 event,
1522*bb4ee6a4SAndroid Build Coastguard Worker                 &mut vm_control_ids_to_remove,
1523*bb4ee6a4SAndroid Build Coastguard Worker                 &mut next_control_id,
1524*bb4ee6a4SAndroid Build Coastguard Worker                 &mut service_vm_state,
1525*bb4ee6a4SAndroid Build Coastguard Worker                 disk_host_tubes.as_slice(),
1526*bb4ee6a4SAndroid Build Coastguard Worker                 ipc_main_loop_tube.as_ref(),
1527*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "gpu")]
1528*bb4ee6a4SAndroid Build Coastguard Worker                 gpu_control_tube.as_ref(),
1529*bb4ee6a4SAndroid Build Coastguard Worker                 &vm_evt_rdtube,
1530*bb4ee6a4SAndroid Build Coastguard Worker                 &mut control_tubes,
1531*bb4ee6a4SAndroid Build Coastguard Worker                 &mut guest_os,
1532*bb4ee6a4SAndroid Build Coastguard Worker                 &sys_allocator_mutex,
1533*bb4ee6a4SAndroid Build Coastguard Worker                 &mut virtio_snd_host_mute_tubes,
1534*bb4ee6a4SAndroid Build Coastguard Worker                 proto_main_loop_tube.as_ref(),
1535*bb4ee6a4SAndroid Build Coastguard Worker                 &anti_tamper_main_thread_tube,
1536*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "balloon")]
1537*bb4ee6a4SAndroid Build Coastguard Worker                 balloon_tube.as_mut(),
1538*bb4ee6a4SAndroid Build Coastguard Worker                 memory_size_mb,
1539*bb4ee6a4SAndroid Build Coastguard Worker                 vcpu_boxes.as_ref(),
1540*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "pvclock")]
1541*bb4ee6a4SAndroid Build Coastguard Worker                 &pvclock_host_tube,
1542*bb4ee6a4SAndroid Build Coastguard Worker                 run_mode_arc.as_ref(),
1543*bb4ee6a4SAndroid Build Coastguard Worker                 &mut region_state,
1544*bb4ee6a4SAndroid Build Coastguard Worker                 vm_control_server.as_mut(),
1545*bb4ee6a4SAndroid Build Coastguard Worker                 &irq_handler_control,
1546*bb4ee6a4SAndroid Build Coastguard Worker                 &device_ctrl_tube,
1547*bb4ee6a4SAndroid Build Coastguard Worker                 &wait_ctx,
1548*bb4ee6a4SAndroid Build Coastguard Worker                 force_s2idle,
1549*bb4ee6a4SAndroid Build Coastguard Worker                 &vcpu_control_channels,
1550*bb4ee6a4SAndroid Build Coastguard Worker                 &mut suspended_pvclock_state,
1551*bb4ee6a4SAndroid Build Coastguard Worker             )?;
1552*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(state) = state {
1553*bb4ee6a4SAndroid Build Coastguard Worker                 exit_state = state;
1554*bb4ee6a4SAndroid Build Coastguard Worker                 break 'poll;
1555*bb4ee6a4SAndroid Build Coastguard Worker             }
1556*bb4ee6a4SAndroid Build Coastguard Worker         }
1557*bb4ee6a4SAndroid Build Coastguard Worker 
1558*bb4ee6a4SAndroid Build Coastguard Worker         remove_closed_tubes(&wait_ctx, &mut control_tubes, vm_control_ids_to_remove)?;
1559*bb4ee6a4SAndroid Build Coastguard Worker     }
1560*bb4ee6a4SAndroid Build Coastguard Worker 
1561*bb4ee6a4SAndroid Build Coastguard Worker     info!("run_control poll loop completed, forcing vCPUs to exit...");
1562*bb4ee6a4SAndroid Build Coastguard Worker 
1563*bb4ee6a4SAndroid Build Coastguard Worker     // VCPU threads MUST see the VmRunMode flag, otherwise they may re-enter the VM.
1564*bb4ee6a4SAndroid Build Coastguard Worker     run_mode_arc.set_and_notify(VmRunMode::Exiting);
1565*bb4ee6a4SAndroid Build Coastguard Worker 
1566*bb4ee6a4SAndroid Build Coastguard Worker     // Force all vcpus to exit from the hypervisor
1567*bb4ee6a4SAndroid Build Coastguard Worker     for vcpu in vcpu_boxes.lock().iter() {
1568*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_immediate_exit(true);
1569*bb4ee6a4SAndroid Build Coastguard Worker     }
1570*bb4ee6a4SAndroid Build Coastguard Worker 
1571*bb4ee6a4SAndroid Build Coastguard Worker     let mut res = Ok(exit_state);
1572*bb4ee6a4SAndroid Build Coastguard Worker     guest_os.irq_chip.kick_halted_vcpus();
1573*bb4ee6a4SAndroid Build Coastguard Worker     let _ = exit_evt.signal();
1574*bb4ee6a4SAndroid Build Coastguard Worker 
1575*bb4ee6a4SAndroid Build Coastguard Worker     if guest_os.devices_thread.is_some() {
1576*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = device_ctrl_tube.send(&DeviceControlCommand::Exit) {
1577*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed to stop device control loop: {}", e);
1578*bb4ee6a4SAndroid Build Coastguard Worker         };
1579*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(thread) = guest_os.devices_thread.take() {
1580*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = thread.join() {
1581*bb4ee6a4SAndroid Build Coastguard Worker                 error!("failed to exit devices thread: {:?}", e);
1582*bb4ee6a4SAndroid Build Coastguard Worker             }
1583*bb4ee6a4SAndroid Build Coastguard Worker         }
1584*bb4ee6a4SAndroid Build Coastguard Worker     }
1585*bb4ee6a4SAndroid Build Coastguard Worker 
1586*bb4ee6a4SAndroid Build Coastguard Worker     // Shut down the VM memory handler thread.
1587*bb4ee6a4SAndroid Build Coastguard Worker     if let Err(e) = vm_memory_handler_control.send(&VmMemoryHandlerRequest::Exit) {
1588*bb4ee6a4SAndroid Build Coastguard Worker         error!(
1589*bb4ee6a4SAndroid Build Coastguard Worker             "failed to request exit from VM memory handler thread: {}",
1590*bb4ee6a4SAndroid Build Coastguard Worker             e
1591*bb4ee6a4SAndroid Build Coastguard Worker         );
1592*bb4ee6a4SAndroid Build Coastguard Worker     }
1593*bb4ee6a4SAndroid Build Coastguard Worker     if let Err(e) = vm_memory_handler_thread_join_handle.join() {
1594*bb4ee6a4SAndroid Build Coastguard Worker         error!("failed to exit VM Memory handler thread: {:?}", e);
1595*bb4ee6a4SAndroid Build Coastguard Worker     }
1596*bb4ee6a4SAndroid Build Coastguard Worker 
1597*bb4ee6a4SAndroid Build Coastguard Worker     // Shut down the IRQ handler thread.
1598*bb4ee6a4SAndroid Build Coastguard Worker     if let Err(e) = irq_handler_control.send(&IrqHandlerRequest::Exit) {
1599*bb4ee6a4SAndroid Build Coastguard Worker         error!("failed to request exit from IRQ handler thread: {}", e);
1600*bb4ee6a4SAndroid Build Coastguard Worker     }
1601*bb4ee6a4SAndroid Build Coastguard Worker 
1602*bb4ee6a4SAndroid Build Coastguard Worker     // Ensure any child threads have ended by sending the Exit vm event (possibly again) to ensure
1603*bb4ee6a4SAndroid Build Coastguard Worker     // their run loops are aborted.
1604*bb4ee6a4SAndroid Build Coastguard Worker     let _ = vm_evt_wrtube.send::<VmEventType>(&VmEventType::Exit);
1605*bb4ee6a4SAndroid Build Coastguard Worker     for (i, thread) in vcpu_threads.into_iter().enumerate() {
1606*bb4ee6a4SAndroid Build Coastguard Worker         // wait till all the threads exit, so that guest_os.vm arc memory count is down to 1.
1607*bb4ee6a4SAndroid Build Coastguard Worker         // otherwise, we will hit a memory leak if we force kill the thread with terminate.
1608*bb4ee6a4SAndroid Build Coastguard Worker         match thread.join() {
1609*bb4ee6a4SAndroid Build Coastguard Worker             Ok(Err(e)) => {
1610*bb4ee6a4SAndroid Build Coastguard Worker                 error!("vcpu thread {} exited with an error: {}", i, e);
1611*bb4ee6a4SAndroid Build Coastguard Worker                 res = Err(e);
1612*bb4ee6a4SAndroid Build Coastguard Worker             }
1613*bb4ee6a4SAndroid Build Coastguard Worker             Ok(_) => {}
1614*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => error!("vcpu thread {} panicked: {:?}", i, e),
1615*bb4ee6a4SAndroid Build Coastguard Worker         }
1616*bb4ee6a4SAndroid Build Coastguard Worker     }
1617*bb4ee6a4SAndroid Build Coastguard Worker 
1618*bb4ee6a4SAndroid Build Coastguard Worker     info!("vCPU threads have exited.");
1619*bb4ee6a4SAndroid Build Coastguard Worker 
1620*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(ime) = ime_thread {
1621*bb4ee6a4SAndroid Build Coastguard Worker         match ime.join() {
1622*bb4ee6a4SAndroid Build Coastguard Worker             Ok(Err(e)) => {
1623*bb4ee6a4SAndroid Build Coastguard Worker                 error!("ime thread exited with an error: {}", e);
1624*bb4ee6a4SAndroid Build Coastguard Worker                 if res.is_ok() {
1625*bb4ee6a4SAndroid Build Coastguard Worker                     // Prioritize past errors, but return this error if it is unique, otherwise just
1626*bb4ee6a4SAndroid Build Coastguard Worker                     // log it.
1627*bb4ee6a4SAndroid Build Coastguard Worker                     res = Err(e)
1628*bb4ee6a4SAndroid Build Coastguard Worker                 }
1629*bb4ee6a4SAndroid Build Coastguard Worker             }
1630*bb4ee6a4SAndroid Build Coastguard Worker             Ok(_) => {}
1631*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => error!("ime thread panicked: {:?}", e),
1632*bb4ee6a4SAndroid Build Coastguard Worker         }
1633*bb4ee6a4SAndroid Build Coastguard Worker     }
1634*bb4ee6a4SAndroid Build Coastguard Worker     info!("IME thread has exited.");
1635*bb4ee6a4SAndroid Build Coastguard Worker 
1636*bb4ee6a4SAndroid Build Coastguard Worker     // This cancels all the outstanding and any future blocking operations.
1637*bb4ee6a4SAndroid Build Coastguard Worker     // TODO(b/196911556): Shutdown executor for cleaner shutdown. Given we are using global, for a
1638*bb4ee6a4SAndroid Build Coastguard Worker     // cleaner shutdown we have to call disarm so that all the incoming requests are run and are
1639*bb4ee6a4SAndroid Build Coastguard Worker     // cancelled. If we call shutdown all blocking threads will go away and incoming operations
1640*bb4ee6a4SAndroid Build Coastguard Worker     // won't be scheduled to run and will be dropped leading to panic. I think ideal place to call
1641*bb4ee6a4SAndroid Build Coastguard Worker     // shutdown is when we drop non-global executor.
1642*bb4ee6a4SAndroid Build Coastguard Worker     cros_async::unblock_disarm();
1643*bb4ee6a4SAndroid Build Coastguard Worker     info!("blocking async pool has shut down.");
1644*bb4ee6a4SAndroid Build Coastguard Worker 
1645*bb4ee6a4SAndroid Build Coastguard Worker     let _ = irq_join_handle.join();
1646*bb4ee6a4SAndroid Build Coastguard Worker     info!("IrqWaitWorker has shut down.");
1647*bb4ee6a4SAndroid Build Coastguard Worker 
1648*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "stats")]
1649*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(stats) = stats {
1650*bb4ee6a4SAndroid Build Coastguard Worker         println!("Statistics Collected:\n{}", stats.lock());
1651*bb4ee6a4SAndroid Build Coastguard Worker         println!("Statistics JSON:\n{}", stats.lock().json());
1652*bb4ee6a4SAndroid Build Coastguard Worker     }
1653*bb4ee6a4SAndroid Build Coastguard Worker 
1654*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(mode) = original_terminal_mode {
1655*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = stdin().restore_mode(mode) {
1656*bb4ee6a4SAndroid Build Coastguard Worker             warn!("failed to restore terminal mode: {}", e);
1657*bb4ee6a4SAndroid Build Coastguard Worker         }
1658*bb4ee6a4SAndroid Build Coastguard Worker     }
1659*bb4ee6a4SAndroid Build Coastguard Worker 
1660*bb4ee6a4SAndroid Build Coastguard Worker     // Explicitly drop the VM structure here to allow the devices to clean up before the
1661*bb4ee6a4SAndroid Build Coastguard Worker     // control tubes are closed when this function exits.
1662*bb4ee6a4SAndroid Build Coastguard Worker     mem::drop(guest_os);
1663*bb4ee6a4SAndroid Build Coastguard Worker 
1664*bb4ee6a4SAndroid Build Coastguard Worker     info!("guest_os dropped, run_control is done.");
1665*bb4ee6a4SAndroid Build Coastguard Worker 
1666*bb4ee6a4SAndroid Build Coastguard Worker     res
1667*bb4ee6a4SAndroid Build Coastguard Worker }
1668*bb4ee6a4SAndroid Build Coastguard Worker 
1669*bb4ee6a4SAndroid Build Coastguard Worker /// Remove Tubes that have been closed from the WaitContext.
1670*bb4ee6a4SAndroid Build Coastguard Worker fn remove_closed_tubes<T, U>(
1671*bb4ee6a4SAndroid Build Coastguard Worker     wait_ctx: &WaitContext<T>,
1672*bb4ee6a4SAndroid Build Coastguard Worker     tubes: &mut BTreeMap<usize, U>,
1673*bb4ee6a4SAndroid Build Coastguard Worker     mut tube_ids_to_remove: Vec<usize>,
1674*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()>
1675*bb4ee6a4SAndroid Build Coastguard Worker where
1676*bb4ee6a4SAndroid Build Coastguard Worker     T: EventToken,
1677*bb4ee6a4SAndroid Build Coastguard Worker     U: ReadNotifier + CloseNotifier,
1678*bb4ee6a4SAndroid Build Coastguard Worker {
1679*bb4ee6a4SAndroid Build Coastguard Worker     tube_ids_to_remove.dedup();
1680*bb4ee6a4SAndroid Build Coastguard Worker     for id in tube_ids_to_remove {
1681*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(socket) = tubes.remove(&id) {
1682*bb4ee6a4SAndroid Build Coastguard Worker             wait_ctx
1683*bb4ee6a4SAndroid Build Coastguard Worker                 .delete(socket.get_read_notifier())
1684*bb4ee6a4SAndroid Build Coastguard Worker                 .context("failed to remove descriptor from wait context")?;
1685*bb4ee6a4SAndroid Build Coastguard Worker 
1686*bb4ee6a4SAndroid Build Coastguard Worker             // There may be a close notifier registered for this Tube. If there isn't one
1687*bb4ee6a4SAndroid Build Coastguard Worker             // registered, we just ignore the error.
1688*bb4ee6a4SAndroid Build Coastguard Worker             let _ = wait_ctx.delete(socket.get_close_notifier());
1689*bb4ee6a4SAndroid Build Coastguard Worker         }
1690*bb4ee6a4SAndroid Build Coastguard Worker     }
1691*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
1692*bb4ee6a4SAndroid Build Coastguard Worker }
1693*bb4ee6a4SAndroid Build Coastguard Worker 
1694*bb4ee6a4SAndroid Build Coastguard Worker /// Sends a message to all VCPUs.
1695*bb4ee6a4SAndroid Build Coastguard Worker fn kick_all_vcpus(
1696*bb4ee6a4SAndroid Build Coastguard Worker     run_mode: &VcpuRunMode,
1697*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_control_channels: &[mpsc::Sender<VcpuControl>],
1698*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_boxes: &Mutex<Vec<Box<dyn VcpuArch>>>,
1699*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip: &dyn IrqChipArch,
1700*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")] pvclock_host_tube: &Option<Tube>,
1701*bb4ee6a4SAndroid Build Coastguard Worker     resume_notify_devices: &[Arc<Mutex<dyn BusResumeDevice>>],
1702*bb4ee6a4SAndroid Build Coastguard Worker     msg: VcpuControl,
1703*bb4ee6a4SAndroid Build Coastguard Worker ) {
1704*bb4ee6a4SAndroid Build Coastguard Worker     // On Windows, we handle run mode switching directly rather than delegating to the VCPU thread
1705*bb4ee6a4SAndroid Build Coastguard Worker     // like unix does.
1706*bb4ee6a4SAndroid Build Coastguard Worker     match &msg {
1707*bb4ee6a4SAndroid Build Coastguard Worker         VcpuControl::RunState(VmRunMode::Suspending) => {
1708*bb4ee6a4SAndroid Build Coastguard Worker             suspend_all_vcpus(
1709*bb4ee6a4SAndroid Build Coastguard Worker                 run_mode,
1710*bb4ee6a4SAndroid Build Coastguard Worker                 vcpu_boxes,
1711*bb4ee6a4SAndroid Build Coastguard Worker                 irq_chip,
1712*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "pvclock")]
1713*bb4ee6a4SAndroid Build Coastguard Worker                 pvclock_host_tube,
1714*bb4ee6a4SAndroid Build Coastguard Worker             );
1715*bb4ee6a4SAndroid Build Coastguard Worker             return;
1716*bb4ee6a4SAndroid Build Coastguard Worker         }
1717*bb4ee6a4SAndroid Build Coastguard Worker         VcpuControl::RunState(VmRunMode::Running) => {
1718*bb4ee6a4SAndroid Build Coastguard Worker             for device in resume_notify_devices {
1719*bb4ee6a4SAndroid Build Coastguard Worker                 device.lock().resume_imminent();
1720*bb4ee6a4SAndroid Build Coastguard Worker             }
1721*bb4ee6a4SAndroid Build Coastguard Worker             resume_all_vcpus(
1722*bb4ee6a4SAndroid Build Coastguard Worker                 run_mode,
1723*bb4ee6a4SAndroid Build Coastguard Worker                 vcpu_boxes,
1724*bb4ee6a4SAndroid Build Coastguard Worker                 irq_chip,
1725*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "pvclock")]
1726*bb4ee6a4SAndroid Build Coastguard Worker                 pvclock_host_tube,
1727*bb4ee6a4SAndroid Build Coastguard Worker             );
1728*bb4ee6a4SAndroid Build Coastguard Worker             return;
1729*bb4ee6a4SAndroid Build Coastguard Worker         }
1730*bb4ee6a4SAndroid Build Coastguard Worker         _ => (),
1731*bb4ee6a4SAndroid Build Coastguard Worker     }
1732*bb4ee6a4SAndroid Build Coastguard Worker 
1733*bb4ee6a4SAndroid Build Coastguard Worker     // For non RunState commands, we dispatch just like unix would.
1734*bb4ee6a4SAndroid Build Coastguard Worker     for vcpu in vcpu_control_channels {
1735*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = vcpu.send(msg.clone()) {
1736*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed to send VcpuControl message: {}", e);
1737*bb4ee6a4SAndroid Build Coastguard Worker         }
1738*bb4ee6a4SAndroid Build Coastguard Worker     }
1739*bb4ee6a4SAndroid Build Coastguard Worker 
1740*bb4ee6a4SAndroid Build Coastguard Worker     // Now that we've sent a message, we need VCPUs to exit so they can process it.
1741*bb4ee6a4SAndroid Build Coastguard Worker     for vcpu in vcpu_boxes.lock().iter() {
1742*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_immediate_exit(true);
1743*bb4ee6a4SAndroid Build Coastguard Worker     }
1744*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip.kick_halted_vcpus();
1745*bb4ee6a4SAndroid Build Coastguard Worker 
1746*bb4ee6a4SAndroid Build Coastguard Worker     // If the VCPU isn't running, we have to notify the run_mode condvar to wake it so it processes
1747*bb4ee6a4SAndroid Build Coastguard Worker     // the control message.
1748*bb4ee6a4SAndroid Build Coastguard Worker     let current_run_mode = run_mode.get_mode();
1749*bb4ee6a4SAndroid Build Coastguard Worker     if current_run_mode != VmRunMode::Running {
1750*bb4ee6a4SAndroid Build Coastguard Worker         run_mode.set_and_notify(current_run_mode);
1751*bb4ee6a4SAndroid Build Coastguard Worker     }
1752*bb4ee6a4SAndroid Build Coastguard Worker }
1753*bb4ee6a4SAndroid Build Coastguard Worker 
1754*bb4ee6a4SAndroid Build Coastguard Worker /// Sends a message to a single VCPU. On Windows, `VcpuControl::RunState` cannot be sent to a single
1755*bb4ee6a4SAndroid Build Coastguard Worker /// VCPU.
1756*bb4ee6a4SAndroid Build Coastguard Worker fn kick_vcpu(
1757*bb4ee6a4SAndroid Build Coastguard Worker     run_mode: &VcpuRunMode,
1758*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_control_channels: &[mpsc::Sender<VcpuControl>],
1759*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_boxes: &Mutex<Vec<Box<dyn VcpuArch>>>,
1760*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip: &dyn IrqChipArch,
1761*bb4ee6a4SAndroid Build Coastguard Worker     index: usize,
1762*bb4ee6a4SAndroid Build Coastguard Worker     msg: VcpuControl,
1763*bb4ee6a4SAndroid Build Coastguard Worker ) {
1764*bb4ee6a4SAndroid Build Coastguard Worker     assert!(
1765*bb4ee6a4SAndroid Build Coastguard Worker         !matches!(msg, VcpuControl::RunState(_)),
1766*bb4ee6a4SAndroid Build Coastguard Worker         "Windows does not support RunState changes on a per VCPU basis"
1767*bb4ee6a4SAndroid Build Coastguard Worker     );
1768*bb4ee6a4SAndroid Build Coastguard Worker 
1769*bb4ee6a4SAndroid Build Coastguard Worker     let vcpu = vcpu_control_channels
1770*bb4ee6a4SAndroid Build Coastguard Worker         .get(index)
1771*bb4ee6a4SAndroid Build Coastguard Worker         .expect("invalid vcpu index specified");
1772*bb4ee6a4SAndroid Build Coastguard Worker     if let Err(e) = vcpu.send(msg) {
1773*bb4ee6a4SAndroid Build Coastguard Worker         error!("failed to send VcpuControl message: {}", e);
1774*bb4ee6a4SAndroid Build Coastguard Worker     }
1775*bb4ee6a4SAndroid Build Coastguard Worker 
1776*bb4ee6a4SAndroid Build Coastguard Worker     // Now that we've sent a message, we need the VCPU to exit so it can
1777*bb4ee6a4SAndroid Build Coastguard Worker     // process the message.
1778*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_boxes
1779*bb4ee6a4SAndroid Build Coastguard Worker         .lock()
1780*bb4ee6a4SAndroid Build Coastguard Worker         .get(index)
1781*bb4ee6a4SAndroid Build Coastguard Worker         .expect("invalid vcpu index specified")
1782*bb4ee6a4SAndroid Build Coastguard Worker         .set_immediate_exit(true);
1783*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip.kick_halted_vcpus();
1784*bb4ee6a4SAndroid Build Coastguard Worker 
1785*bb4ee6a4SAndroid Build Coastguard Worker     // If the VCPU isn't running, we have to notify the run_mode condvar to wake it so it processes
1786*bb4ee6a4SAndroid Build Coastguard Worker     // the control message. (Technically this wakes all VCPUs, but those without messages will go
1787*bb4ee6a4SAndroid Build Coastguard Worker     // back to sleep.)
1788*bb4ee6a4SAndroid Build Coastguard Worker     let current_run_mode = run_mode.get_mode();
1789*bb4ee6a4SAndroid Build Coastguard Worker     if current_run_mode != VmRunMode::Running {
1790*bb4ee6a4SAndroid Build Coastguard Worker         run_mode.set_and_notify(current_run_mode);
1791*bb4ee6a4SAndroid Build Coastguard Worker     }
1792*bb4ee6a4SAndroid Build Coastguard Worker }
1793*bb4ee6a4SAndroid Build Coastguard Worker 
1794*bb4ee6a4SAndroid Build Coastguard Worker /// Suspends all VCPUs. The VM will be effectively frozen in time once this function is called,
1795*bb4ee6a4SAndroid Build Coastguard Worker /// though devices on the host will continue to run.
1796*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn suspend_all_vcpus(
1797*bb4ee6a4SAndroid Build Coastguard Worker     run_mode: &VcpuRunMode,
1798*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_boxes: &Mutex<Vec<Box<dyn VcpuArch>>>,
1799*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip: &dyn IrqChipArch,
1800*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")] pvclock_host_tube: &Option<Tube>,
1801*bb4ee6a4SAndroid Build Coastguard Worker ) {
1802*bb4ee6a4SAndroid Build Coastguard Worker     // VCPU threads MUST see the VmRunMode::Suspending flag first, otherwise
1803*bb4ee6a4SAndroid Build Coastguard Worker     // they may re-enter the VM.
1804*bb4ee6a4SAndroid Build Coastguard Worker     run_mode.set_and_notify(VmRunMode::Suspending);
1805*bb4ee6a4SAndroid Build Coastguard Worker 
1806*bb4ee6a4SAndroid Build Coastguard Worker     // Force all vcpus to exit from the hypervisor
1807*bb4ee6a4SAndroid Build Coastguard Worker     for vcpu in vcpu_boxes.lock().iter() {
1808*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_immediate_exit(true);
1809*bb4ee6a4SAndroid Build Coastguard Worker     }
1810*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip.kick_halted_vcpus();
1811*bb4ee6a4SAndroid Build Coastguard Worker 
1812*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")]
1813*bb4ee6a4SAndroid Build Coastguard Worker     handle_pvclock_request(pvclock_host_tube, PvClockCommand::Suspend)
1814*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap_or_else(|e| error!("Error handling pvclock suspend: {:?}", e));
1815*bb4ee6a4SAndroid Build Coastguard Worker }
1816*bb4ee6a4SAndroid Build Coastguard Worker 
1817*bb4ee6a4SAndroid Build Coastguard Worker /// Resumes all VCPUs.
1818*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn resume_all_vcpus(
1819*bb4ee6a4SAndroid Build Coastguard Worker     run_mode: &VcpuRunMode,
1820*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_boxes: &Mutex<Vec<Box<dyn VcpuArch>>>,
1821*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip: &dyn IrqChipArch,
1822*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")] pvclock_host_tube: &Option<Tube>,
1823*bb4ee6a4SAndroid Build Coastguard Worker ) {
1824*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")]
1825*bb4ee6a4SAndroid Build Coastguard Worker     handle_pvclock_request(pvclock_host_tube, PvClockCommand::Resume)
1826*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap_or_else(|e| error!("Error handling pvclock resume: {:?}", e));
1827*bb4ee6a4SAndroid Build Coastguard Worker 
1828*bb4ee6a4SAndroid Build Coastguard Worker     // Make sure any immediate exit bits are disabled
1829*bb4ee6a4SAndroid Build Coastguard Worker     for vcpu in vcpu_boxes.lock().iter() {
1830*bb4ee6a4SAndroid Build Coastguard Worker         vcpu.set_immediate_exit(false);
1831*bb4ee6a4SAndroid Build Coastguard Worker     }
1832*bb4ee6a4SAndroid Build Coastguard Worker 
1833*bb4ee6a4SAndroid Build Coastguard Worker     run_mode.set_and_notify(VmRunMode::Running);
1834*bb4ee6a4SAndroid Build Coastguard Worker }
1835*bb4ee6a4SAndroid Build Coastguard Worker 
1836*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
1837*bb4ee6a4SAndroid Build Coastguard Worker const GVM_MINIMUM_VERSION: GvmVersion = GvmVersion {
1838*bb4ee6a4SAndroid Build Coastguard Worker     major: 1,
1839*bb4ee6a4SAndroid Build Coastguard Worker     minor: 4,
1840*bb4ee6a4SAndroid Build Coastguard Worker     patch: 1,
1841*bb4ee6a4SAndroid Build Coastguard Worker };
1842*bb4ee6a4SAndroid Build Coastguard Worker 
1843*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
1844*bb4ee6a4SAndroid Build Coastguard Worker fn create_gvm_vm(gvm: Gvm, mem: GuestMemory) -> Result<GvmVm> {
1845*bb4ee6a4SAndroid Build Coastguard Worker     match gvm.get_full_version() {
1846*bb4ee6a4SAndroid Build Coastguard Worker         Ok(version) => {
1847*bb4ee6a4SAndroid Build Coastguard Worker             if version < GVM_MINIMUM_VERSION {
1848*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
1849*bb4ee6a4SAndroid Build Coastguard Worker                     "GVM version {} is below minimum version {}",
1850*bb4ee6a4SAndroid Build Coastguard Worker                     version, GVM_MINIMUM_VERSION
1851*bb4ee6a4SAndroid Build Coastguard Worker                 );
1852*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(base::Error::new(libc::ENXIO).into());
1853*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1854*bb4ee6a4SAndroid Build Coastguard Worker                 info!("Using GVM version {}.", version)
1855*bb4ee6a4SAndroid Build Coastguard Worker             }
1856*bb4ee6a4SAndroid Build Coastguard Worker         }
1857*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
1858*bb4ee6a4SAndroid Build Coastguard Worker             error!("unable to determine gvm version: {}", e);
1859*bb4ee6a4SAndroid Build Coastguard Worker             return Err(base::Error::new(libc::ENXIO).into());
1860*bb4ee6a4SAndroid Build Coastguard Worker         }
1861*bb4ee6a4SAndroid Build Coastguard Worker     }
1862*bb4ee6a4SAndroid Build Coastguard Worker     let vm = GvmVm::new(&gvm, mem)?;
1863*bb4ee6a4SAndroid Build Coastguard Worker     Ok(vm)
1864*bb4ee6a4SAndroid Build Coastguard Worker }
1865*bb4ee6a4SAndroid Build Coastguard Worker 
1866*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "haxm")]
1867*bb4ee6a4SAndroid Build Coastguard Worker fn create_haxm_vm(
1868*bb4ee6a4SAndroid Build Coastguard Worker     haxm: Haxm,
1869*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
1870*bb4ee6a4SAndroid Build Coastguard Worker     kernel_log_file: &Option<String>,
1871*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<HaxmVm> {
1872*bb4ee6a4SAndroid Build Coastguard Worker     let vm = HaxmVm::new(&haxm, mem)?;
1873*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(path) = kernel_log_file {
1874*bb4ee6a4SAndroid Build Coastguard Worker         use hypervisor::haxm::HAX_CAP_VM_LOG;
1875*bb4ee6a4SAndroid Build Coastguard Worker         if vm.check_raw_capability(HAX_CAP_VM_LOG) {
1876*bb4ee6a4SAndroid Build Coastguard Worker             match vm.register_log_file(path) {
1877*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => {}
1878*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => match e.errno() {
1879*bb4ee6a4SAndroid Build Coastguard Worker                     libc::E2BIG => {
1880*bb4ee6a4SAndroid Build Coastguard Worker                         error!(
1881*bb4ee6a4SAndroid Build Coastguard Worker                             "kernel_log_file path is too long, kernel log file will not be written"
1882*bb4ee6a4SAndroid Build Coastguard Worker                         );
1883*bb4ee6a4SAndroid Build Coastguard Worker                     }
1884*bb4ee6a4SAndroid Build Coastguard Worker                     _ => return Err(e.into()),
1885*bb4ee6a4SAndroid Build Coastguard Worker                 },
1886*bb4ee6a4SAndroid Build Coastguard Worker             }
1887*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1888*bb4ee6a4SAndroid Build Coastguard Worker             warn!(
1889*bb4ee6a4SAndroid Build Coastguard Worker                 "kernel_log_file specified but this version of HAXM does not support kernel log \
1890*bb4ee6a4SAndroid Build Coastguard Worker                   files"
1891*bb4ee6a4SAndroid Build Coastguard Worker             );
1892*bb4ee6a4SAndroid Build Coastguard Worker         }
1893*bb4ee6a4SAndroid Build Coastguard Worker     }
1894*bb4ee6a4SAndroid Build Coastguard Worker     Ok(vm)
1895*bb4ee6a4SAndroid Build Coastguard Worker }
1896*bb4ee6a4SAndroid Build Coastguard Worker 
1897*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
1898*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")]
1899*bb4ee6a4SAndroid Build Coastguard Worker fn create_whpx_vm(
1900*bb4ee6a4SAndroid Build Coastguard Worker     whpx: Whpx,
1901*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
1902*bb4ee6a4SAndroid Build Coastguard Worker     cpu_count: usize,
1903*bb4ee6a4SAndroid Build Coastguard Worker     no_smt: bool,
1904*bb4ee6a4SAndroid Build Coastguard Worker     apic_emulation: bool,
1905*bb4ee6a4SAndroid Build Coastguard Worker     force_calibrated_tsc_leaf: bool,
1906*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_wrtube: SendTube,
1907*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<WhpxVm> {
1908*bb4ee6a4SAndroid Build Coastguard Worker     let cpu_config = hypervisor::CpuConfigX86_64::new(
1909*bb4ee6a4SAndroid Build Coastguard Worker         force_calibrated_tsc_leaf,
1910*bb4ee6a4SAndroid Build Coastguard Worker         false, /* host_cpu_topology */
1911*bb4ee6a4SAndroid Build Coastguard Worker         false, /* enable_hwp */
1912*bb4ee6a4SAndroid Build Coastguard Worker         no_smt,
1913*bb4ee6a4SAndroid Build Coastguard Worker         false, /* itmt */
1914*bb4ee6a4SAndroid Build Coastguard Worker         None,  /* hybrid_type */
1915*bb4ee6a4SAndroid Build Coastguard Worker     );
1916*bb4ee6a4SAndroid Build Coastguard Worker 
1917*bb4ee6a4SAndroid Build Coastguard Worker     // context for non-cpu-specific cpuid results
1918*bb4ee6a4SAndroid Build Coastguard Worker     let ctx = CpuIdContext::new(
1919*bb4ee6a4SAndroid Build Coastguard Worker         0,
1920*bb4ee6a4SAndroid Build Coastguard Worker         cpu_count,
1921*bb4ee6a4SAndroid Build Coastguard Worker         None,
1922*bb4ee6a4SAndroid Build Coastguard Worker         cpu_config,
1923*bb4ee6a4SAndroid Build Coastguard Worker         whpx.check_capability(HypervisorCap::CalibratedTscLeafRequired),
1924*bb4ee6a4SAndroid Build Coastguard Worker         __cpuid_count,
1925*bb4ee6a4SAndroid Build Coastguard Worker         __cpuid,
1926*bb4ee6a4SAndroid Build Coastguard Worker     );
1927*bb4ee6a4SAndroid Build Coastguard Worker 
1928*bb4ee6a4SAndroid Build Coastguard Worker     // Get all cpuid entries that we should pre-set
1929*bb4ee6a4SAndroid Build Coastguard Worker     let mut cpuid = whpx.get_supported_cpuid()?;
1930*bb4ee6a4SAndroid Build Coastguard Worker 
1931*bb4ee6a4SAndroid Build Coastguard Worker     // Adjust them for crosvm
1932*bb4ee6a4SAndroid Build Coastguard Worker     for entry in cpuid.cpu_id_entries.iter_mut() {
1933*bb4ee6a4SAndroid Build Coastguard Worker         adjust_cpuid(entry, &ctx);
1934*bb4ee6a4SAndroid Build Coastguard Worker     }
1935*bb4ee6a4SAndroid Build Coastguard Worker 
1936*bb4ee6a4SAndroid Build Coastguard Worker     let vm = WhpxVm::new(
1937*bb4ee6a4SAndroid Build Coastguard Worker         &whpx,
1938*bb4ee6a4SAndroid Build Coastguard Worker         cpu_count,
1939*bb4ee6a4SAndroid Build Coastguard Worker         mem,
1940*bb4ee6a4SAndroid Build Coastguard Worker         cpuid,
1941*bb4ee6a4SAndroid Build Coastguard Worker         apic_emulation,
1942*bb4ee6a4SAndroid Build Coastguard Worker         Some(vm_evt_wrtube),
1943*bb4ee6a4SAndroid Build Coastguard Worker     )
1944*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(Exit::WhpxSetupError, "failed to create WHPX vm")?;
1945*bb4ee6a4SAndroid Build Coastguard Worker 
1946*bb4ee6a4SAndroid Build Coastguard Worker     Ok(vm)
1947*bb4ee6a4SAndroid Build Coastguard Worker }
1948*bb4ee6a4SAndroid Build Coastguard Worker 
1949*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gvm")]
1950*bb4ee6a4SAndroid Build Coastguard Worker fn create_gvm_irq_chip(vm: &GvmVm, vcpu_count: usize) -> base::Result<GvmIrqChip> {
1951*bb4ee6a4SAndroid Build Coastguard Worker     info!("Creating GVM irqchip");
1952*bb4ee6a4SAndroid Build Coastguard Worker     let irq_chip = GvmIrqChip::new(vm.try_clone()?, vcpu_count)?;
1953*bb4ee6a4SAndroid Build Coastguard Worker     Ok(irq_chip)
1954*bb4ee6a4SAndroid Build Coastguard Worker }
1955*bb4ee6a4SAndroid Build Coastguard Worker 
1956*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "whpx")]
1957*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")]
1958*bb4ee6a4SAndroid Build Coastguard Worker fn create_whpx_split_irq_chip(
1959*bb4ee6a4SAndroid Build Coastguard Worker     vm: &WhpxVm,
1960*bb4ee6a4SAndroid Build Coastguard Worker     ioapic_device_tube: Tube,
1961*bb4ee6a4SAndroid Build Coastguard Worker ) -> base::Result<WhpxSplitIrqChip> {
1962*bb4ee6a4SAndroid Build Coastguard Worker     info!("Creating WHPX split irqchip");
1963*bb4ee6a4SAndroid Build Coastguard Worker     WhpxSplitIrqChip::new(
1964*bb4ee6a4SAndroid Build Coastguard Worker         vm.try_clone()?,
1965*bb4ee6a4SAndroid Build Coastguard Worker         ioapic_device_tube,
1966*bb4ee6a4SAndroid Build Coastguard Worker         None, // ioapic_pins
1967*bb4ee6a4SAndroid Build Coastguard Worker     )
1968*bb4ee6a4SAndroid Build Coastguard Worker }
1969*bb4ee6a4SAndroid Build Coastguard Worker 
1970*bb4ee6a4SAndroid Build Coastguard Worker fn create_userspace_irq_chip<Vcpu>(
1971*bb4ee6a4SAndroid Build Coastguard Worker     vcpu_count: usize,
1972*bb4ee6a4SAndroid Build Coastguard Worker     ioapic_device_tube: Tube,
1973*bb4ee6a4SAndroid Build Coastguard Worker ) -> base::Result<UserspaceIrqChip<Vcpu>>
1974*bb4ee6a4SAndroid Build Coastguard Worker where
1975*bb4ee6a4SAndroid Build Coastguard Worker     Vcpu: VcpuArch + 'static,
1976*bb4ee6a4SAndroid Build Coastguard Worker {
1977*bb4ee6a4SAndroid Build Coastguard Worker     info!("Creating userspace irqchip");
1978*bb4ee6a4SAndroid Build Coastguard Worker     let irq_chip =
1979*bb4ee6a4SAndroid Build Coastguard Worker         UserspaceIrqChip::new(vcpu_count, ioapic_device_tube, /* ioapic_pins: */ None)?;
1980*bb4ee6a4SAndroid Build Coastguard Worker     Ok(irq_chip)
1981*bb4ee6a4SAndroid Build Coastguard Worker }
1982*bb4ee6a4SAndroid Build Coastguard Worker 
1983*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_default_hypervisor() -> Option<HypervisorKind> {
1984*bb4ee6a4SAndroid Build Coastguard Worker     // The ordering here matters from most preferable to the least.
1985*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "whpx")]
1986*bb4ee6a4SAndroid Build Coastguard Worker     match hypervisor::whpx::Whpx::is_enabled() {
1987*bb4ee6a4SAndroid Build Coastguard Worker         true => return Some(HypervisorKind::Whpx),
1988*bb4ee6a4SAndroid Build Coastguard Worker         false => warn!("Whpx not enabled."),
1989*bb4ee6a4SAndroid Build Coastguard Worker     };
1990*bb4ee6a4SAndroid Build Coastguard Worker 
1991*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "haxm")]
1992*bb4ee6a4SAndroid Build Coastguard Worker     match Haxm::new() {
1993*bb4ee6a4SAndroid Build Coastguard Worker         Ok(_) => return Some(HypervisorKind::Ghaxm),
1994*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => warn!("Cannot initialize HAXM: {}", e),
1995*bb4ee6a4SAndroid Build Coastguard Worker     };
1996*bb4ee6a4SAndroid Build Coastguard Worker 
1997*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gvm")]
1998*bb4ee6a4SAndroid Build Coastguard Worker     // Make sure Gvm device can be opened before selecting it.
1999*bb4ee6a4SAndroid Build Coastguard Worker     match Gvm::new() {
2000*bb4ee6a4SAndroid Build Coastguard Worker         Ok(_) => return Some(HypervisorKind::Gvm),
2001*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => warn!("Cannot initialize GVM: {}", e),
2002*bb4ee6a4SAndroid Build Coastguard Worker     };
2003*bb4ee6a4SAndroid Build Coastguard Worker 
2004*bb4ee6a4SAndroid Build Coastguard Worker     None
2005*bb4ee6a4SAndroid Build Coastguard Worker }
2006*bb4ee6a4SAndroid Build Coastguard Worker 
2007*bb4ee6a4SAndroid Build Coastguard Worker fn setup_vm_components(cfg: &Config) -> Result<VmComponents> {
2008*bb4ee6a4SAndroid Build Coastguard Worker     let initrd_image = if let Some(initrd_path) = &cfg.initrd_path {
2009*bb4ee6a4SAndroid Build Coastguard Worker         Some(
2010*bb4ee6a4SAndroid Build Coastguard Worker             File::open(initrd_path).with_exit_context(Exit::OpenInitrd, || {
2011*bb4ee6a4SAndroid Build Coastguard Worker                 format!("failed to open initrd {}", initrd_path.display())
2012*bb4ee6a4SAndroid Build Coastguard Worker             })?,
2013*bb4ee6a4SAndroid Build Coastguard Worker         )
2014*bb4ee6a4SAndroid Build Coastguard Worker     } else {
2015*bb4ee6a4SAndroid Build Coastguard Worker         None
2016*bb4ee6a4SAndroid Build Coastguard Worker     };
2017*bb4ee6a4SAndroid Build Coastguard Worker 
2018*bb4ee6a4SAndroid Build Coastguard Worker     let vm_image = match cfg.executable_path {
2019*bb4ee6a4SAndroid Build Coastguard Worker         Some(Executable::Kernel(ref kernel_path)) => VmImage::Kernel(
2020*bb4ee6a4SAndroid Build Coastguard Worker             File::open(kernel_path).with_exit_context(Exit::OpenKernel, || {
2021*bb4ee6a4SAndroid Build Coastguard Worker                 format!("failed to open kernel image {}", kernel_path.display(),)
2022*bb4ee6a4SAndroid Build Coastguard Worker             })?,
2023*bb4ee6a4SAndroid Build Coastguard Worker         ),
2024*bb4ee6a4SAndroid Build Coastguard Worker         Some(Executable::Bios(ref bios_path)) => {
2025*bb4ee6a4SAndroid Build Coastguard Worker             VmImage::Bios(File::open(bios_path).with_exit_context(Exit::OpenBios, || {
2026*bb4ee6a4SAndroid Build Coastguard Worker                 format!("failed to open bios {}", bios_path.display())
2027*bb4ee6a4SAndroid Build Coastguard Worker             })?)
2028*bb4ee6a4SAndroid Build Coastguard Worker         }
2029*bb4ee6a4SAndroid Build Coastguard Worker         _ => panic!("Did not receive a bios or kernel, should be impossible."),
2030*bb4ee6a4SAndroid Build Coastguard Worker     };
2031*bb4ee6a4SAndroid Build Coastguard Worker 
2032*bb4ee6a4SAndroid Build Coastguard Worker     let swiotlb = if let Some(size) = cfg.swiotlb {
2033*bb4ee6a4SAndroid Build Coastguard Worker         Some(
2034*bb4ee6a4SAndroid Build Coastguard Worker             size.checked_mul(1024 * 1024)
2035*bb4ee6a4SAndroid Build Coastguard Worker                 .ok_or_else(|| anyhow!("requested swiotlb size too large"))?,
2036*bb4ee6a4SAndroid Build Coastguard Worker         )
2037*bb4ee6a4SAndroid Build Coastguard Worker     } else if matches!(cfg.protection_type, ProtectionType::Unprotected) {
2038*bb4ee6a4SAndroid Build Coastguard Worker         None
2039*bb4ee6a4SAndroid Build Coastguard Worker     } else {
2040*bb4ee6a4SAndroid Build Coastguard Worker         Some(64 * 1024 * 1024)
2041*bb4ee6a4SAndroid Build Coastguard Worker     };
2042*bb4ee6a4SAndroid Build Coastguard Worker 
2043*bb4ee6a4SAndroid Build Coastguard Worker     let (pflash_image, pflash_block_size) = if let Some(pflash_parameters) = &cfg.pflash_parameters
2044*bb4ee6a4SAndroid Build Coastguard Worker     {
2045*bb4ee6a4SAndroid Build Coastguard Worker         (
2046*bb4ee6a4SAndroid Build Coastguard Worker             Some(
2047*bb4ee6a4SAndroid Build Coastguard Worker                 open_file_or_duplicate(
2048*bb4ee6a4SAndroid Build Coastguard Worker                     &pflash_parameters.path,
2049*bb4ee6a4SAndroid Build Coastguard Worker                     OpenOptions::new().read(true).write(true),
2050*bb4ee6a4SAndroid Build Coastguard Worker                 )
2051*bb4ee6a4SAndroid Build Coastguard Worker                 .with_context(|| {
2052*bb4ee6a4SAndroid Build Coastguard Worker                     format!("failed to open pflash {}", pflash_parameters.path.display())
2053*bb4ee6a4SAndroid Build Coastguard Worker                 })?,
2054*bb4ee6a4SAndroid Build Coastguard Worker             ),
2055*bb4ee6a4SAndroid Build Coastguard Worker             pflash_parameters.block_size,
2056*bb4ee6a4SAndroid Build Coastguard Worker         )
2057*bb4ee6a4SAndroid Build Coastguard Worker     } else {
2058*bb4ee6a4SAndroid Build Coastguard Worker         (None, 0)
2059*bb4ee6a4SAndroid Build Coastguard Worker     };
2060*bb4ee6a4SAndroid Build Coastguard Worker 
2061*bb4ee6a4SAndroid Build Coastguard Worker     Ok(VmComponents {
2062*bb4ee6a4SAndroid Build Coastguard Worker         memory_size: cfg
2063*bb4ee6a4SAndroid Build Coastguard Worker             .memory
2064*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap_or(256)
2065*bb4ee6a4SAndroid Build Coastguard Worker             .checked_mul(1024 * 1024)
2066*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or_else(|| anyhow!("requested memory size too large"))?,
2067*bb4ee6a4SAndroid Build Coastguard Worker         swiotlb,
2068*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_count: cfg.vcpu_count.unwrap_or(1),
2069*bb4ee6a4SAndroid Build Coastguard Worker         fw_cfg_enable: false,
2070*bb4ee6a4SAndroid Build Coastguard Worker         bootorder_fw_cfg_blob: Vec::new(),
2071*bb4ee6a4SAndroid Build Coastguard Worker         vcpu_affinity: cfg.vcpu_affinity.clone(),
2072*bb4ee6a4SAndroid Build Coastguard Worker         cpu_clusters: cfg.cpu_clusters.clone(),
2073*bb4ee6a4SAndroid Build Coastguard Worker         cpu_capacity: cfg.cpu_capacity.clone(),
2074*bb4ee6a4SAndroid Build Coastguard Worker         no_smt: cfg.no_smt,
2075*bb4ee6a4SAndroid Build Coastguard Worker         hugepages: cfg.hugepages,
2076*bb4ee6a4SAndroid Build Coastguard Worker         hv_cfg: hypervisor::Config {
2077*bb4ee6a4SAndroid Build Coastguard Worker             protection_type: cfg.protection_type,
2078*bb4ee6a4SAndroid Build Coastguard Worker         },
2079*bb4ee6a4SAndroid Build Coastguard Worker         vm_image,
2080*bb4ee6a4SAndroid Build Coastguard Worker         android_fstab: cfg
2081*bb4ee6a4SAndroid Build Coastguard Worker             .android_fstab
2082*bb4ee6a4SAndroid Build Coastguard Worker             .as_ref()
2083*bb4ee6a4SAndroid Build Coastguard Worker             .map(|x| {
2084*bb4ee6a4SAndroid Build Coastguard Worker                 File::open(x).with_exit_context(Exit::OpenAndroidFstab, || {
2085*bb4ee6a4SAndroid Build Coastguard Worker                     format!("failed to open android fstab file {}", x.display())
2086*bb4ee6a4SAndroid Build Coastguard Worker                 })
2087*bb4ee6a4SAndroid Build Coastguard Worker             })
2088*bb4ee6a4SAndroid Build Coastguard Worker             .map_or(Ok(None), |v| v.map(Some))?,
2089*bb4ee6a4SAndroid Build Coastguard Worker         pstore: cfg.pstore.clone(),
2090*bb4ee6a4SAndroid Build Coastguard Worker         pflash_block_size,
2091*bb4ee6a4SAndroid Build Coastguard Worker         pflash_image,
2092*bb4ee6a4SAndroid Build Coastguard Worker         initrd_image,
2093*bb4ee6a4SAndroid Build Coastguard Worker         extra_kernel_params: cfg.params.clone(),
2094*bb4ee6a4SAndroid Build Coastguard Worker         acpi_sdts: cfg
2095*bb4ee6a4SAndroid Build Coastguard Worker             .acpi_tables
2096*bb4ee6a4SAndroid Build Coastguard Worker             .iter()
2097*bb4ee6a4SAndroid Build Coastguard Worker             .map(|path| {
2098*bb4ee6a4SAndroid Build Coastguard Worker                 SDT::from_file(path).with_exit_context(Exit::OpenAcpiTable, || {
2099*bb4ee6a4SAndroid Build Coastguard Worker                     format!("failed to open ACPI file {}", path.display())
2100*bb4ee6a4SAndroid Build Coastguard Worker                 })
2101*bb4ee6a4SAndroid Build Coastguard Worker             })
2102*bb4ee6a4SAndroid Build Coastguard Worker             .collect::<Result<Vec<SDT>>>()?,
2103*bb4ee6a4SAndroid Build Coastguard Worker         rt_cpus: cfg.rt_cpus.clone(),
2104*bb4ee6a4SAndroid Build Coastguard Worker         delay_rt: cfg.delay_rt,
2105*bb4ee6a4SAndroid Build Coastguard Worker         no_i8042: cfg.no_i8042,
2106*bb4ee6a4SAndroid Build Coastguard Worker         no_rtc: cfg.no_rtc,
2107*bb4ee6a4SAndroid Build Coastguard Worker         host_cpu_topology: cfg.host_cpu_topology,
2108*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(target_arch = "x86_64")]
2109*bb4ee6a4SAndroid Build Coastguard Worker         force_s2idle: cfg.force_s2idle,
2110*bb4ee6a4SAndroid Build Coastguard Worker         fw_cfg_parameters: cfg.fw_cfg_parameters.clone(),
2111*bb4ee6a4SAndroid Build Coastguard Worker         itmt: false,
2112*bb4ee6a4SAndroid Build Coastguard Worker         pvm_fw: None,
2113*bb4ee6a4SAndroid Build Coastguard Worker         pci_config: cfg.pci_config,
2114*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(target_arch = "x86_64")]
2115*bb4ee6a4SAndroid Build Coastguard Worker         smbios: cfg.smbios.clone(),
2116*bb4ee6a4SAndroid Build Coastguard Worker         dynamic_power_coefficient: cfg.dynamic_power_coefficient.clone(),
2117*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(target_arch = "x86_64")]
2118*bb4ee6a4SAndroid Build Coastguard Worker         break_linux_pci_config_io: cfg.break_linux_pci_config_io,
2119*bb4ee6a4SAndroid Build Coastguard Worker         boot_cpu: cfg.boot_cpu,
2120*bb4ee6a4SAndroid Build Coastguard Worker     })
2121*bb4ee6a4SAndroid Build Coastguard Worker }
2122*bb4ee6a4SAndroid Build Coastguard Worker 
2123*bb4ee6a4SAndroid Build Coastguard Worker // Enum that allows us to assign a variable to what is essentially a &dyn IrqChipArch.
2124*bb4ee6a4SAndroid Build Coastguard Worker enum WindowsIrqChip<V: VcpuArch> {
2125*bb4ee6a4SAndroid Build Coastguard Worker     Userspace(UserspaceIrqChip<V>),
2126*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gvm")]
2127*bb4ee6a4SAndroid Build Coastguard Worker     Gvm(GvmIrqChip),
2128*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "whpx")]
2129*bb4ee6a4SAndroid Build Coastguard Worker     WhpxSplit(WhpxSplitIrqChip),
2130*bb4ee6a4SAndroid Build Coastguard Worker }
2131*bb4ee6a4SAndroid Build Coastguard Worker 
2132*bb4ee6a4SAndroid Build Coastguard Worker impl<V: VcpuArch> WindowsIrqChip<V> {
2133*bb4ee6a4SAndroid Build Coastguard Worker     // Convert our enum to a &mut dyn IrqChipArch
2134*bb4ee6a4SAndroid Build Coastguard Worker     fn as_mut(&mut self) -> &mut dyn IrqChipArch {
2135*bb4ee6a4SAndroid Build Coastguard Worker         match self {
2136*bb4ee6a4SAndroid Build Coastguard Worker             WindowsIrqChip::Userspace(i) => i,
2137*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "gvm")]
2138*bb4ee6a4SAndroid Build Coastguard Worker             WindowsIrqChip::Gvm(i) => i,
2139*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "whpx")]
2140*bb4ee6a4SAndroid Build Coastguard Worker             WindowsIrqChip::WhpxSplit(i) => i,
2141*bb4ee6a4SAndroid Build Coastguard Worker         }
2142*bb4ee6a4SAndroid Build Coastguard Worker     }
2143*bb4ee6a4SAndroid Build Coastguard Worker }
2144*bb4ee6a4SAndroid Build Coastguard Worker 
2145*bb4ee6a4SAndroid Build Coastguard Worker /// Storage for the VM TSC offset for each vcpu. Stored in a static because the tracing thread will
2146*bb4ee6a4SAndroid Build Coastguard Worker /// need access to it when tracing is enabled.
2147*bb4ee6a4SAndroid Build Coastguard Worker static TSC_OFFSETS: sync::Mutex<Vec<Option<u64>>> = sync::Mutex::new(Vec::new());
2148*bb4ee6a4SAndroid Build Coastguard Worker 
2149*bb4ee6a4SAndroid Build Coastguard Worker /// Save the TSC offset for a particular vcpu.
2150*bb4ee6a4SAndroid Build Coastguard Worker ///
2151*bb4ee6a4SAndroid Build Coastguard Worker /// After setting the TSC offset for a vcpu, this function checks the standard deviation of offsets
2152*bb4ee6a4SAndroid Build Coastguard Worker /// for all the VCPUs and logs this information. If the TSC offsets differ too much between vcpus
2153*bb4ee6a4SAndroid Build Coastguard Worker /// it can cause clock issues in the guest.
2154*bb4ee6a4SAndroid Build Coastguard Worker pub fn save_vcpu_tsc_offset(offset: u64, vcpu_id: usize) {
2155*bb4ee6a4SAndroid Build Coastguard Worker     let offsets_copy = {
2156*bb4ee6a4SAndroid Build Coastguard Worker         let mut offsets = TSC_OFFSETS.lock();
2157*bb4ee6a4SAndroid Build Coastguard Worker         // make sure offsets vec is large enough before inserting
2158*bb4ee6a4SAndroid Build Coastguard Worker         let newlen = std::cmp::max(offsets.len(), vcpu_id + 1);
2159*bb4ee6a4SAndroid Build Coastguard Worker         offsets.resize(newlen, None);
2160*bb4ee6a4SAndroid Build Coastguard Worker         offsets[vcpu_id] = Some(offset);
2161*bb4ee6a4SAndroid Build Coastguard Worker 
2162*bb4ee6a4SAndroid Build Coastguard Worker         offsets.clone()
2163*bb4ee6a4SAndroid Build Coastguard Worker     };
2164*bb4ee6a4SAndroid Build Coastguard Worker 
2165*bb4ee6a4SAndroid Build Coastguard Worker     // do statistics on a clone of the offsets so we don't hold up other vcpus at this point
2166*bb4ee6a4SAndroid Build Coastguard Worker     info!(
2167*bb4ee6a4SAndroid Build Coastguard Worker         "TSC offset standard deviation is: {}",
2168*bb4ee6a4SAndroid Build Coastguard Worker         standard_deviation(
2169*bb4ee6a4SAndroid Build Coastguard Worker             &offsets_copy
2170*bb4ee6a4SAndroid Build Coastguard Worker                 .iter()
2171*bb4ee6a4SAndroid Build Coastguard Worker                 .filter(|x| x.is_some())
2172*bb4ee6a4SAndroid Build Coastguard Worker                 .map(|x| x.unwrap() as u128)
2173*bb4ee6a4SAndroid Build Coastguard Worker                 .collect::<Vec<u128>>()
2174*bb4ee6a4SAndroid Build Coastguard Worker         )
2175*bb4ee6a4SAndroid Build Coastguard Worker     );
2176*bb4ee6a4SAndroid Build Coastguard Worker }
2177*bb4ee6a4SAndroid Build Coastguard Worker 
2178*bb4ee6a4SAndroid Build Coastguard Worker /// Get the TSC offset of any vcpu. It will pick the first non-None offset it finds in TSC_OFFSETS.
2179*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "perfetto")]
2180*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_vcpu_tsc_offset() -> u64 {
2181*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(offset) = TSC_OFFSETS.lock().iter().flatten().next() {
2182*bb4ee6a4SAndroid Build Coastguard Worker         return *offset;
2183*bb4ee6a4SAndroid Build Coastguard Worker     }
2184*bb4ee6a4SAndroid Build Coastguard Worker     0
2185*bb4ee6a4SAndroid Build Coastguard Worker }
2186*bb4ee6a4SAndroid Build Coastguard Worker 
2187*bb4ee6a4SAndroid Build Coastguard Worker /// Callback that is registered with tracing crate, and will be called by the tracing thread when
2188*bb4ee6a4SAndroid Build Coastguard Worker /// tracing is enabled or disabled. Regardless of whether tracing is being enabled or disabled for
2189*bb4ee6a4SAndroid Build Coastguard Worker /// a given category or instance, we just emit a clock snapshot that maps the guest TSC to the
2190*bb4ee6a4SAndroid Build Coastguard Worker /// host TSC. Redundant snapshots should not be a problem for perfetto.
2191*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "perfetto")]
2192*bb4ee6a4SAndroid Build Coastguard Worker fn set_tsc_clock_snapshot() {
2193*bb4ee6a4SAndroid Build Coastguard Worker     let freq = match devices::tsc::tsc_frequency() {
2194*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
2195*bb4ee6a4SAndroid Build Coastguard Worker             error!(
2196*bb4ee6a4SAndroid Build Coastguard Worker                 "Could not determine tsc frequency, unable to snapshot tsc offset: {}",
2197*bb4ee6a4SAndroid Build Coastguard Worker                 e
2198*bb4ee6a4SAndroid Build Coastguard Worker             );
2199*bb4ee6a4SAndroid Build Coastguard Worker             return;
2200*bb4ee6a4SAndroid Build Coastguard Worker         }
2201*bb4ee6a4SAndroid Build Coastguard Worker         Ok(freq) => freq,
2202*bb4ee6a4SAndroid Build Coastguard Worker     };
2203*bb4ee6a4SAndroid Build Coastguard Worker 
2204*bb4ee6a4SAndroid Build Coastguard Worker     // The offset is host-guest tsc value
2205*bb4ee6a4SAndroid Build Coastguard Worker     let offset = get_vcpu_tsc_offset();
2206*bb4ee6a4SAndroid Build Coastguard Worker     // Safe because _rdtsc takes no arguments;
2207*bb4ee6a4SAndroid Build Coastguard Worker     let host_tsc = unsafe { std::arch::x86_64::_rdtsc() };
2208*bb4ee6a4SAndroid Build Coastguard Worker     perfetto::snapshot_clock(perfetto::ClockSnapshot::new(
2209*bb4ee6a4SAndroid Build Coastguard Worker         // Technically our multiplier should be freq/1_000_000_000, but perfetto doesn't
2210*bb4ee6a4SAndroid Build Coastguard Worker         // support floating point multipliers yet. So for now we set the freq in Hz and rely
2211*bb4ee6a4SAndroid Build Coastguard Worker         // on the merge tool to fix it.
2212*bb4ee6a4SAndroid Build Coastguard Worker         perfetto::Clock::new(
2213*bb4ee6a4SAndroid Build Coastguard Worker             perfetto::BuiltinClock::Tsc as u32,
2214*bb4ee6a4SAndroid Build Coastguard Worker             host_tsc.wrapping_add(offset),
2215*bb4ee6a4SAndroid Build Coastguard Worker         )
2216*bb4ee6a4SAndroid Build Coastguard Worker         .set_multiplier(freq as u64),
2217*bb4ee6a4SAndroid Build Coastguard Worker         perfetto::Clock::new(
2218*bb4ee6a4SAndroid Build Coastguard Worker             // The host builtin clock ids are all offset from the guest ids by
2219*bb4ee6a4SAndroid Build Coastguard Worker             // HOST_GUEST_CLOCK_ID_OFFSET when the traces are merged. Because this snapshot
2220*bb4ee6a4SAndroid Build Coastguard Worker             // contains both a guest and host clock, we need to offset it before merge.
2221*bb4ee6a4SAndroid Build Coastguard Worker             perfetto::BuiltinClock::Tsc as u32 + cros_tracing::HOST_GUEST_CLOCK_ID_OFFSET,
2222*bb4ee6a4SAndroid Build Coastguard Worker             host_tsc,
2223*bb4ee6a4SAndroid Build Coastguard Worker         )
2224*bb4ee6a4SAndroid Build Coastguard Worker         .set_multiplier(freq as u64),
2225*bb4ee6a4SAndroid Build Coastguard Worker     ));
2226*bb4ee6a4SAndroid Build Coastguard Worker }
2227*bb4ee6a4SAndroid Build Coastguard Worker 
2228*bb4ee6a4SAndroid Build Coastguard Worker /// Launches run_config for the broker, reading configuration from a TubeTransporter.
2229*bb4ee6a4SAndroid Build Coastguard Worker pub fn run_config_for_broker(raw_tube_transporter: RawDescriptor) -> Result<ExitState> {
2230*bb4ee6a4SAndroid Build Coastguard Worker     let tube_transporter =
2231*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
2232*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we know that raw_transport_tube is valid (passed by inheritance), and that
2233*bb4ee6a4SAndroid Build Coastguard Worker         // the blocking & framing modes are accurate because we create them ourselves in the broker.
2234*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { TubeTransporterReader::from_raw_descriptor(raw_tube_transporter) };
2235*bb4ee6a4SAndroid Build Coastguard Worker 
2236*bb4ee6a4SAndroid Build Coastguard Worker     let mut tube_data_list = tube_transporter
2237*bb4ee6a4SAndroid Build Coastguard Worker         .read_tubes()
2238*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::TubeTransporterInit, "failed to init tube transporter")?;
2239*bb4ee6a4SAndroid Build Coastguard Worker 
2240*bb4ee6a4SAndroid Build Coastguard Worker     let bootstrap_tube = tube_data_list
2241*bb4ee6a4SAndroid Build Coastguard Worker         .get_tube(TubeToken::Bootstrap)
2242*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::TubeFailure, "failed to get bootstrap tube")?;
2243*bb4ee6a4SAndroid Build Coastguard Worker 
2244*bb4ee6a4SAndroid Build Coastguard Worker     let mut cfg: Config = bootstrap_tube
2245*bb4ee6a4SAndroid Build Coastguard Worker         .recv::<Config>()
2246*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::TubeFailure, "failed to read bootstrap tube")?;
2247*bb4ee6a4SAndroid Build Coastguard Worker 
2248*bb4ee6a4SAndroid Build Coastguard Worker     let startup_args: CommonChildStartupArgs = bootstrap_tube
2249*bb4ee6a4SAndroid Build Coastguard Worker         .recv::<CommonChildStartupArgs>()
2250*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::TubeFailure, "failed to read bootstrap tube")?;
2251*bb4ee6a4SAndroid Build Coastguard Worker     let _child_cleanup = common_child_setup(startup_args).exit_context(
2252*bb4ee6a4SAndroid Build Coastguard Worker         Exit::CommonChildSetupError,
2253*bb4ee6a4SAndroid Build Coastguard Worker         "failed to perform common child setup",
2254*bb4ee6a4SAndroid Build Coastguard Worker     )?;
2255*bb4ee6a4SAndroid Build Coastguard Worker 
2256*bb4ee6a4SAndroid Build Coastguard Worker     cfg.broker_shutdown_event = Some(
2257*bb4ee6a4SAndroid Build Coastguard Worker         bootstrap_tube
2258*bb4ee6a4SAndroid Build Coastguard Worker             .recv::<Event>()
2259*bb4ee6a4SAndroid Build Coastguard Worker             .exit_context(Exit::TubeFailure, "failed to read bootstrap tube")?,
2260*bb4ee6a4SAndroid Build Coastguard Worker     );
2261*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "crash-report")]
2262*bb4ee6a4SAndroid Build Coastguard Worker     let crash_tube_map = bootstrap_tube
2263*bb4ee6a4SAndroid Build Coastguard Worker         .recv::<HashMap<ProcessType, Vec<SendTube>>>()
2264*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::TubeFailure, "failed to read bootstrap tube")?;
2265*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "crash-report")]
2266*bb4ee6a4SAndroid Build Coastguard Worker     crash_report::set_crash_tube_map(crash_tube_map);
2267*bb4ee6a4SAndroid Build Coastguard Worker 
2268*bb4ee6a4SAndroid Build Coastguard Worker     let BrokerTubes {
2269*bb4ee6a4SAndroid Build Coastguard Worker         vm_evt_wrtube,
2270*bb4ee6a4SAndroid Build Coastguard Worker         vm_evt_rdtube,
2271*bb4ee6a4SAndroid Build Coastguard Worker     } = bootstrap_tube
2272*bb4ee6a4SAndroid Build Coastguard Worker         .recv::<BrokerTubes>()
2273*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::TubeFailure, "failed to read bootstrap tube")?;
2274*bb4ee6a4SAndroid Build Coastguard Worker 
2275*bb4ee6a4SAndroid Build Coastguard Worker     run_config_inner(cfg, vm_evt_wrtube, vm_evt_rdtube)
2276*bb4ee6a4SAndroid Build Coastguard Worker }
2277*bb4ee6a4SAndroid Build Coastguard Worker 
2278*bb4ee6a4SAndroid Build Coastguard Worker pub fn run_config(cfg: Config) -> Result<ExitState> {
2279*bb4ee6a4SAndroid Build Coastguard Worker     let _raise_timer_resolution = enable_high_res_timers()
2280*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::EnableHighResTimer, "failed to enable high res timer")?;
2281*bb4ee6a4SAndroid Build Coastguard Worker 
2282*bb4ee6a4SAndroid Build Coastguard Worker     // There is no broker when using run_config(), so the vm_evt tubes need to be created.
2283*bb4ee6a4SAndroid Build Coastguard Worker     let (vm_evt_wrtube, vm_evt_rdtube) =
2284*bb4ee6a4SAndroid Build Coastguard Worker         Tube::directional_pair().context("failed to create vm event tube")?;
2285*bb4ee6a4SAndroid Build Coastguard Worker 
2286*bb4ee6a4SAndroid Build Coastguard Worker     run_config_inner(cfg, vm_evt_wrtube, vm_evt_rdtube)
2287*bb4ee6a4SAndroid Build Coastguard Worker }
2288*bb4ee6a4SAndroid Build Coastguard Worker 
2289*bb4ee6a4SAndroid Build Coastguard Worker fn create_guest_memory(
2290*bb4ee6a4SAndroid Build Coastguard Worker     components: &VmComponents,
2291*bb4ee6a4SAndroid Build Coastguard Worker     arch_memory_layout: &<Arch as LinuxArch>::ArchMemoryLayout,
2292*bb4ee6a4SAndroid Build Coastguard Worker     hypervisor: &impl Hypervisor,
2293*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<GuestMemory> {
2294*bb4ee6a4SAndroid Build Coastguard Worker     let guest_mem_layout = Arch::guest_memory_layout(components, arch_memory_layout, hypervisor)
2295*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(
2296*bb4ee6a4SAndroid Build Coastguard Worker             Exit::GuestMemoryLayout,
2297*bb4ee6a4SAndroid Build Coastguard Worker             "failed to create guest memory layout",
2298*bb4ee6a4SAndroid Build Coastguard Worker         )?;
2299*bb4ee6a4SAndroid Build Coastguard Worker     GuestMemory::new_with_options(&guest_mem_layout)
2300*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::CreateGuestMemory, "failed to create guest memory")
2301*bb4ee6a4SAndroid Build Coastguard Worker }
2302*bb4ee6a4SAndroid Build Coastguard Worker 
2303*bb4ee6a4SAndroid Build Coastguard Worker fn run_config_inner(
2304*bb4ee6a4SAndroid Build Coastguard Worker     cfg: Config,
2305*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_wrtube: SendTube,
2306*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_rdtube: RecvTube,
2307*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<ExitState> {
2308*bb4ee6a4SAndroid Build Coastguard Worker     product::setup_common_metric_invariants(&cfg);
2309*bb4ee6a4SAndroid Build Coastguard Worker 
2310*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "perfetto")]
2311*bb4ee6a4SAndroid Build Coastguard Worker     cros_tracing::add_per_trace_callback(set_tsc_clock_snapshot);
2312*bb4ee6a4SAndroid Build Coastguard Worker 
2313*bb4ee6a4SAndroid Build Coastguard Worker     let components: VmComponents = setup_vm_components(&cfg)?;
2314*bb4ee6a4SAndroid Build Coastguard Worker     let arch_memory_layout = Arch::arch_memory_layout(&components)?;
2315*bb4ee6a4SAndroid Build Coastguard Worker 
2316*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(unused_mut)]
2317*bb4ee6a4SAndroid Build Coastguard Worker     let mut hypervisor = cfg
2318*bb4ee6a4SAndroid Build Coastguard Worker         .hypervisor
2319*bb4ee6a4SAndroid Build Coastguard Worker         .or_else(get_default_hypervisor)
2320*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::NoDefaultHypervisor, "no enabled hypervisor")?;
2321*bb4ee6a4SAndroid Build Coastguard Worker 
2322*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "whpx")]
2323*bb4ee6a4SAndroid Build Coastguard Worker     if hypervisor::whpx::Whpx::is_enabled() {
2324*bb4ee6a4SAndroid Build Coastguard Worker         // If WHPX is enabled, no other hypervisor can be used, so just override it
2325*bb4ee6a4SAndroid Build Coastguard Worker         hypervisor = HypervisorKind::Whpx;
2326*bb4ee6a4SAndroid Build Coastguard Worker     }
2327*bb4ee6a4SAndroid Build Coastguard Worker 
2328*bb4ee6a4SAndroid Build Coastguard Worker     match hypervisor {
2329*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "haxm")]
2330*bb4ee6a4SAndroid Build Coastguard Worker         HypervisorKind::Haxm | HypervisorKind::Ghaxm => {
2331*bb4ee6a4SAndroid Build Coastguard Worker             if hypervisor == HypervisorKind::Haxm {
2332*bb4ee6a4SAndroid Build Coastguard Worker                 set_use_ghaxm(false);
2333*bb4ee6a4SAndroid Build Coastguard Worker             }
2334*bb4ee6a4SAndroid Build Coastguard Worker             info!("Creating HAXM ghaxm={}", get_use_ghaxm());
2335*bb4ee6a4SAndroid Build Coastguard Worker             let haxm = Haxm::new()?;
2336*bb4ee6a4SAndroid Build Coastguard Worker             let guest_mem = create_guest_memory(&components, &arch_memory_layout, &haxm)?;
2337*bb4ee6a4SAndroid Build Coastguard Worker             let vm = create_haxm_vm(haxm, guest_mem, &cfg.kernel_log_file)?;
2338*bb4ee6a4SAndroid Build Coastguard Worker             let (ioapic_host_tube, ioapic_device_tube) =
2339*bb4ee6a4SAndroid Build Coastguard Worker                 Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2340*bb4ee6a4SAndroid Build Coastguard Worker             let irq_chip =
2341*bb4ee6a4SAndroid Build Coastguard Worker                 create_userspace_irq_chip::<HaxmVcpu>(components.vcpu_count, ioapic_device_tube)?;
2342*bb4ee6a4SAndroid Build Coastguard Worker             run_vm::<HaxmVcpu, HaxmVm>(
2343*bb4ee6a4SAndroid Build Coastguard Worker                 cfg,
2344*bb4ee6a4SAndroid Build Coastguard Worker                 components,
2345*bb4ee6a4SAndroid Build Coastguard Worker                 &arch_memory_layout,
2346*bb4ee6a4SAndroid Build Coastguard Worker                 vm,
2347*bb4ee6a4SAndroid Build Coastguard Worker                 WindowsIrqChip::Userspace(irq_chip).as_mut(),
2348*bb4ee6a4SAndroid Build Coastguard Worker                 Some(ioapic_host_tube),
2349*bb4ee6a4SAndroid Build Coastguard Worker                 vm_evt_wrtube,
2350*bb4ee6a4SAndroid Build Coastguard Worker                 vm_evt_rdtube,
2351*bb4ee6a4SAndroid Build Coastguard Worker             )
2352*bb4ee6a4SAndroid Build Coastguard Worker         }
2353*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "whpx")]
2354*bb4ee6a4SAndroid Build Coastguard Worker         HypervisorKind::Whpx => {
2355*bb4ee6a4SAndroid Build Coastguard Worker             let apic_emulation_supported =
2356*bb4ee6a4SAndroid Build Coastguard Worker                 Whpx::check_whpx_feature(WhpxFeature::LocalApicEmulation)
2357*bb4ee6a4SAndroid Build Coastguard Worker                     .exit_context(Exit::WhpxSetupError, "failed to set up whpx")?;
2358*bb4ee6a4SAndroid Build Coastguard Worker 
2359*bb4ee6a4SAndroid Build Coastguard Worker             let no_smt = cfg.no_smt;
2360*bb4ee6a4SAndroid Build Coastguard Worker 
2361*bb4ee6a4SAndroid Build Coastguard Worker             // Default to WhpxSplitIrqChip if it's supported because it's more performant
2362*bb4ee6a4SAndroid Build Coastguard Worker             let irq_chip = cfg.irq_chip.unwrap_or(if apic_emulation_supported {
2363*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Split
2364*bb4ee6a4SAndroid Build Coastguard Worker             } else {
2365*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Userspace
2366*bb4ee6a4SAndroid Build Coastguard Worker             });
2367*bb4ee6a4SAndroid Build Coastguard Worker 
2368*bb4ee6a4SAndroid Build Coastguard Worker             // Both WHPX irq chips use a userspace IOAPIC
2369*bb4ee6a4SAndroid Build Coastguard Worker             let (ioapic_host_tube, ioapic_device_tube) =
2370*bb4ee6a4SAndroid Build Coastguard Worker                 Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2371*bb4ee6a4SAndroid Build Coastguard Worker 
2372*bb4ee6a4SAndroid Build Coastguard Worker             info!("Creating Whpx");
2373*bb4ee6a4SAndroid Build Coastguard Worker             let whpx = Whpx::new()?;
2374*bb4ee6a4SAndroid Build Coastguard Worker             let guest_mem = create_guest_memory(&components, &arch_memory_layout, &whpx)?;
2375*bb4ee6a4SAndroid Build Coastguard Worker             let vm = create_whpx_vm(
2376*bb4ee6a4SAndroid Build Coastguard Worker                 whpx,
2377*bb4ee6a4SAndroid Build Coastguard Worker                 guest_mem,
2378*bb4ee6a4SAndroid Build Coastguard Worker                 components.vcpu_count,
2379*bb4ee6a4SAndroid Build Coastguard Worker                 no_smt,
2380*bb4ee6a4SAndroid Build Coastguard Worker                 apic_emulation_supported && irq_chip == IrqChipKind::Split,
2381*bb4ee6a4SAndroid Build Coastguard Worker                 cfg.force_calibrated_tsc_leaf,
2382*bb4ee6a4SAndroid Build Coastguard Worker                 vm_evt_wrtube
2383*bb4ee6a4SAndroid Build Coastguard Worker                     .try_clone()
2384*bb4ee6a4SAndroid Build Coastguard Worker                     .expect("could not clone vm_evt_wrtube"),
2385*bb4ee6a4SAndroid Build Coastguard Worker             )?;
2386*bb4ee6a4SAndroid Build Coastguard Worker 
2387*bb4ee6a4SAndroid Build Coastguard Worker             let mut irq_chip = match irq_chip {
2388*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Kernel => unimplemented!("Kernel irqchip mode not supported by WHPX"),
2389*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Split => {
2390*bb4ee6a4SAndroid Build Coastguard Worker                     if !apic_emulation_supported {
2391*bb4ee6a4SAndroid Build Coastguard Worker                         panic!(
2392*bb4ee6a4SAndroid Build Coastguard Worker                             "split irqchip specified but your WHPX version does not support \
2393*bb4ee6a4SAndroid Build Coastguard Worker                                local apic emulation"
2394*bb4ee6a4SAndroid Build Coastguard Worker                         );
2395*bb4ee6a4SAndroid Build Coastguard Worker                     }
2396*bb4ee6a4SAndroid Build Coastguard Worker                     WindowsIrqChip::WhpxSplit(create_whpx_split_irq_chip(&vm, ioapic_device_tube)?)
2397*bb4ee6a4SAndroid Build Coastguard Worker                 }
2398*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Userspace => {
2399*bb4ee6a4SAndroid Build Coastguard Worker                     WindowsIrqChip::Userspace(create_userspace_irq_chip::<WhpxVcpu>(
2400*bb4ee6a4SAndroid Build Coastguard Worker                         components.vcpu_count,
2401*bb4ee6a4SAndroid Build Coastguard Worker                         ioapic_device_tube,
2402*bb4ee6a4SAndroid Build Coastguard Worker                     )?)
2403*bb4ee6a4SAndroid Build Coastguard Worker                 }
2404*bb4ee6a4SAndroid Build Coastguard Worker             };
2405*bb4ee6a4SAndroid Build Coastguard Worker             run_vm::<WhpxVcpu, WhpxVm>(
2406*bb4ee6a4SAndroid Build Coastguard Worker                 cfg,
2407*bb4ee6a4SAndroid Build Coastguard Worker                 components,
2408*bb4ee6a4SAndroid Build Coastguard Worker                 &arch_memory_layout,
2409*bb4ee6a4SAndroid Build Coastguard Worker                 vm,
2410*bb4ee6a4SAndroid Build Coastguard Worker                 irq_chip.as_mut(),
2411*bb4ee6a4SAndroid Build Coastguard Worker                 Some(ioapic_host_tube),
2412*bb4ee6a4SAndroid Build Coastguard Worker                 vm_evt_wrtube,
2413*bb4ee6a4SAndroid Build Coastguard Worker                 vm_evt_rdtube,
2414*bb4ee6a4SAndroid Build Coastguard Worker             )
2415*bb4ee6a4SAndroid Build Coastguard Worker         }
2416*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "gvm")]
2417*bb4ee6a4SAndroid Build Coastguard Worker         HypervisorKind::Gvm => {
2418*bb4ee6a4SAndroid Build Coastguard Worker             info!("Creating GVM");
2419*bb4ee6a4SAndroid Build Coastguard Worker             let gvm = Gvm::new()?;
2420*bb4ee6a4SAndroid Build Coastguard Worker             let guest_mem = create_guest_memory(&components, &arch_memory_layout, &gvm)?;
2421*bb4ee6a4SAndroid Build Coastguard Worker             let vm = create_gvm_vm(gvm, guest_mem)?;
2422*bb4ee6a4SAndroid Build Coastguard Worker             let ioapic_host_tube;
2423*bb4ee6a4SAndroid Build Coastguard Worker             let mut irq_chip = match cfg.irq_chip.unwrap_or(IrqChipKind::Kernel) {
2424*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Split => unimplemented!("Split irqchip mode not supported by GVM"),
2425*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Kernel => {
2426*bb4ee6a4SAndroid Build Coastguard Worker                     ioapic_host_tube = None;
2427*bb4ee6a4SAndroid Build Coastguard Worker                     WindowsIrqChip::Gvm(create_gvm_irq_chip(&vm, components.vcpu_count)?)
2428*bb4ee6a4SAndroid Build Coastguard Worker                 }
2429*bb4ee6a4SAndroid Build Coastguard Worker                 IrqChipKind::Userspace => {
2430*bb4ee6a4SAndroid Build Coastguard Worker                     let (host_tube, ioapic_device_tube) =
2431*bb4ee6a4SAndroid Build Coastguard Worker                         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2432*bb4ee6a4SAndroid Build Coastguard Worker                     ioapic_host_tube = Some(host_tube);
2433*bb4ee6a4SAndroid Build Coastguard Worker                     WindowsIrqChip::Userspace(create_userspace_irq_chip::<GvmVcpu>(
2434*bb4ee6a4SAndroid Build Coastguard Worker                         components.vcpu_count,
2435*bb4ee6a4SAndroid Build Coastguard Worker                         ioapic_device_tube,
2436*bb4ee6a4SAndroid Build Coastguard Worker                     )?)
2437*bb4ee6a4SAndroid Build Coastguard Worker                 }
2438*bb4ee6a4SAndroid Build Coastguard Worker             };
2439*bb4ee6a4SAndroid Build Coastguard Worker             run_vm::<GvmVcpu, GvmVm>(
2440*bb4ee6a4SAndroid Build Coastguard Worker                 cfg,
2441*bb4ee6a4SAndroid Build Coastguard Worker                 components,
2442*bb4ee6a4SAndroid Build Coastguard Worker                 &arch_memory_layout,
2443*bb4ee6a4SAndroid Build Coastguard Worker                 vm,
2444*bb4ee6a4SAndroid Build Coastguard Worker                 irq_chip.as_mut(),
2445*bb4ee6a4SAndroid Build Coastguard Worker                 ioapic_host_tube,
2446*bb4ee6a4SAndroid Build Coastguard Worker                 vm_evt_wrtube,
2447*bb4ee6a4SAndroid Build Coastguard Worker                 vm_evt_rdtube,
2448*bb4ee6a4SAndroid Build Coastguard Worker             )
2449*bb4ee6a4SAndroid Build Coastguard Worker         }
2450*bb4ee6a4SAndroid Build Coastguard Worker     }
2451*bb4ee6a4SAndroid Build Coastguard Worker }
2452*bb4ee6a4SAndroid Build Coastguard Worker 
2453*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(feature = "haxm", feature = "gvm", feature = "whpx"))]
2454*bb4ee6a4SAndroid Build Coastguard Worker fn run_vm<Vcpu, V>(
2455*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(unused_mut)] mut cfg: Config,
2456*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(unused_mut)] mut components: VmComponents,
2457*bb4ee6a4SAndroid Build Coastguard Worker     arch_memory_layout: &<Arch as LinuxArch>::ArchMemoryLayout,
2458*bb4ee6a4SAndroid Build Coastguard Worker     mut vm: V,
2459*bb4ee6a4SAndroid Build Coastguard Worker     irq_chip: &mut dyn IrqChipArch,
2460*bb4ee6a4SAndroid Build Coastguard Worker     ioapic_host_tube: Option<Tube>,
2461*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_wrtube: SendTube,
2462*bb4ee6a4SAndroid Build Coastguard Worker     vm_evt_rdtube: RecvTube,
2463*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<ExitState>
2464*bb4ee6a4SAndroid Build Coastguard Worker where
2465*bb4ee6a4SAndroid Build Coastguard Worker     Vcpu: VcpuArch + 'static,
2466*bb4ee6a4SAndroid Build Coastguard Worker     V: VmArch + 'static,
2467*bb4ee6a4SAndroid Build Coastguard Worker {
2468*bb4ee6a4SAndroid Build Coastguard Worker     let vm_memory_size_mb = components.memory_size / (1024 * 1024);
2469*bb4ee6a4SAndroid Build Coastguard Worker     let mut control_tubes = Vec::new();
2470*bb4ee6a4SAndroid Build Coastguard Worker     let mut irq_control_tubes = Vec::new();
2471*bb4ee6a4SAndroid Build Coastguard Worker     let mut vm_memory_control_tubes = Vec::new();
2472*bb4ee6a4SAndroid Build Coastguard Worker     // Create one control tube per disk.
2473*bb4ee6a4SAndroid Build Coastguard Worker     let mut disk_device_tubes = Vec::new();
2474*bb4ee6a4SAndroid Build Coastguard Worker     let mut disk_host_tubes = Vec::new();
2475*bb4ee6a4SAndroid Build Coastguard Worker     let disk_count = cfg.disks.len();
2476*bb4ee6a4SAndroid Build Coastguard Worker     for _ in 0..disk_count {
2477*bb4ee6a4SAndroid Build Coastguard Worker         let (disk_host_tube, disk_device_tube) =
2478*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2479*bb4ee6a4SAndroid Build Coastguard Worker         disk_host_tubes.push(disk_host_tube);
2480*bb4ee6a4SAndroid Build Coastguard Worker         disk_device_tubes.push(disk_device_tube);
2481*bb4ee6a4SAndroid Build Coastguard Worker     }
2482*bb4ee6a4SAndroid Build Coastguard Worker 
2483*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(ioapic_host_tube) = ioapic_host_tube {
2484*bb4ee6a4SAndroid Build Coastguard Worker         irq_control_tubes.push(ioapic_host_tube);
2485*bb4ee6a4SAndroid Build Coastguard Worker     }
2486*bb4ee6a4SAndroid Build Coastguard Worker 
2487*bb4ee6a4SAndroid Build Coastguard Worker     // Balloon gets a special socket so balloon requests can be forwarded from the main process.
2488*bb4ee6a4SAndroid Build Coastguard Worker     let (balloon_host_tube, balloon_device_tube) = if cfg.balloon {
2489*bb4ee6a4SAndroid Build Coastguard Worker         let (balloon_host_tube, balloon_device_tube) =
2490*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2491*bb4ee6a4SAndroid Build Coastguard Worker         (Some(balloon_host_tube), Some(balloon_device_tube))
2492*bb4ee6a4SAndroid Build Coastguard Worker     } else {
2493*bb4ee6a4SAndroid Build Coastguard Worker         (None, None)
2494*bb4ee6a4SAndroid Build Coastguard Worker     };
2495*bb4ee6a4SAndroid Build Coastguard Worker     // The balloon device also needs a tube to communicate back to the main process to
2496*bb4ee6a4SAndroid Build Coastguard Worker     // handle remapping memory dynamically.
2497*bb4ee6a4SAndroid Build Coastguard Worker     let dynamic_mapping_device_tube = if cfg.balloon {
2498*bb4ee6a4SAndroid Build Coastguard Worker         let (dynamic_mapping_host_tube, dynamic_mapping_device_tube) =
2499*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2500*bb4ee6a4SAndroid Build Coastguard Worker         vm_memory_control_tubes.push(dynamic_mapping_host_tube);
2501*bb4ee6a4SAndroid Build Coastguard Worker         Some(dynamic_mapping_device_tube)
2502*bb4ee6a4SAndroid Build Coastguard Worker     } else {
2503*bb4ee6a4SAndroid Build Coastguard Worker         None
2504*bb4ee6a4SAndroid Build Coastguard Worker     };
2505*bb4ee6a4SAndroid Build Coastguard Worker 
2506*bb4ee6a4SAndroid Build Coastguard Worker     // PvClock gets a tube for handling suspend/resume requests from the main thread.
2507*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "pvclock")]
2508*bb4ee6a4SAndroid Build Coastguard Worker     let (pvclock_host_tube, pvclock_device_tube) = if cfg.pvclock {
2509*bb4ee6a4SAndroid Build Coastguard Worker         let (host, device) =
2510*bb4ee6a4SAndroid Build Coastguard Worker             Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2511*bb4ee6a4SAndroid Build Coastguard Worker         (Some(host), Some(device))
2512*bb4ee6a4SAndroid Build Coastguard Worker     } else {
2513*bb4ee6a4SAndroid Build Coastguard Worker         (None, None)
2514*bb4ee6a4SAndroid Build Coastguard Worker     };
2515*bb4ee6a4SAndroid Build Coastguard Worker 
2516*bb4ee6a4SAndroid Build Coastguard Worker     let gralloc = RutabagaGralloc::new(RutabagaGrallocBackendFlags::new())
2517*bb4ee6a4SAndroid Build Coastguard Worker         .exit_context(Exit::CreateGralloc, "failed to create gralloc")?;
2518*bb4ee6a4SAndroid Build Coastguard Worker 
2519*bb4ee6a4SAndroid Build Coastguard Worker     let pstore_size = components.pstore.as_ref().map(|pstore| pstore.size as u64);
2520*bb4ee6a4SAndroid Build Coastguard Worker     let mut sys_allocator = SystemAllocator::new(
2521*bb4ee6a4SAndroid Build Coastguard Worker         Arch::get_system_allocator_config(&vm, arch_memory_layout),
2522*bb4ee6a4SAndroid Build Coastguard Worker         pstore_size,
2523*bb4ee6a4SAndroid Build Coastguard Worker         &cfg.mmio_address_ranges,
2524*bb4ee6a4SAndroid Build Coastguard Worker     )
2525*bb4ee6a4SAndroid Build Coastguard Worker     .context("failed to create system allocator")?;
2526*bb4ee6a4SAndroid Build Coastguard Worker 
2527*bb4ee6a4SAndroid Build Coastguard Worker     // Allocate the ramoops region first.
2528*bb4ee6a4SAndroid Build Coastguard Worker     let ramoops_region = match &components.pstore {
2529*bb4ee6a4SAndroid Build Coastguard Worker         Some(pstore) => Some(
2530*bb4ee6a4SAndroid Build Coastguard Worker             arch::pstore::create_memory_region(
2531*bb4ee6a4SAndroid Build Coastguard Worker                 &mut vm,
2532*bb4ee6a4SAndroid Build Coastguard Worker                 sys_allocator.reserved_region().unwrap(),
2533*bb4ee6a4SAndroid Build Coastguard Worker                 pstore,
2534*bb4ee6a4SAndroid Build Coastguard Worker             )
2535*bb4ee6a4SAndroid Build Coastguard Worker             .exit_context(
2536*bb4ee6a4SAndroid Build Coastguard Worker                 Exit::Pstore,
2537*bb4ee6a4SAndroid Build Coastguard Worker                 format!("failed to allocate pstore region {:?}", &components.pstore),
2538*bb4ee6a4SAndroid Build Coastguard Worker             )?,
2539*bb4ee6a4SAndroid Build Coastguard Worker         ),
2540*bb4ee6a4SAndroid Build Coastguard Worker         None => None,
2541*bb4ee6a4SAndroid Build Coastguard Worker     };
2542*bb4ee6a4SAndroid Build Coastguard Worker 
2543*bb4ee6a4SAndroid Build Coastguard Worker     let init_balloon_size = components
2544*bb4ee6a4SAndroid Build Coastguard Worker         .memory_size
2545*bb4ee6a4SAndroid Build Coastguard Worker         .checked_sub(cfg.init_memory.map_or(components.memory_size, |m| {
2546*bb4ee6a4SAndroid Build Coastguard Worker             m.checked_mul(1024 * 1024).unwrap_or(u64::MAX)
2547*bb4ee6a4SAndroid Build Coastguard Worker         }))
2548*bb4ee6a4SAndroid Build Coastguard Worker         .context("failed to calculate init balloon size")?;
2549*bb4ee6a4SAndroid Build Coastguard Worker 
2550*bb4ee6a4SAndroid Build Coastguard Worker     let tsc_state = devices::tsc::tsc_state().exit_code(Exit::TscCalibrationFailed)?;
2551*bb4ee6a4SAndroid Build Coastguard Worker     let tsc_sync_mitigations = get_tsc_sync_mitigations(&tsc_state, components.vcpu_count);
2552*bb4ee6a4SAndroid Build Coastguard Worker 
2553*bb4ee6a4SAndroid Build Coastguard Worker     if tsc_state.core_grouping.size() > 1 {
2554*bb4ee6a4SAndroid Build Coastguard Worker         // Host TSCs are not in sync, log a metric about it.
2555*bb4ee6a4SAndroid Build Coastguard Worker         warn!(
2556*bb4ee6a4SAndroid Build Coastguard Worker             "Host TSCs are not in sync, applying the following mitigations: {:?}",
2557*bb4ee6a4SAndroid Build Coastguard Worker             tsc_sync_mitigations
2558*bb4ee6a4SAndroid Build Coastguard Worker         );
2559*bb4ee6a4SAndroid Build Coastguard Worker         log_descriptor(
2560*bb4ee6a4SAndroid Build Coastguard Worker             MetricEventType::TscCoresOutOfSync,
2561*bb4ee6a4SAndroid Build Coastguard Worker             // casting u64 as i64 is a no-op, so we don't lose any part of the bitmask
2562*bb4ee6a4SAndroid Build Coastguard Worker             tsc_state.core_grouping.core_grouping_bitmask() as i64,
2563*bb4ee6a4SAndroid Build Coastguard Worker         );
2564*bb4ee6a4SAndroid Build Coastguard Worker     }
2565*bb4ee6a4SAndroid Build Coastguard Worker 
2566*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "gpu")]
2567*bb4ee6a4SAndroid Build Coastguard Worker     let gpu_control_tube = cfg
2568*bb4ee6a4SAndroid Build Coastguard Worker         .gpu_vmm_config
2569*bb4ee6a4SAndroid Build Coastguard Worker         .as_mut()
2570*bb4ee6a4SAndroid Build Coastguard Worker         .and_then(|config| config.gpu_control_host_tube.take());
2571*bb4ee6a4SAndroid Build Coastguard Worker     let product_args = product::get_run_control_args(&mut cfg);
2572*bb4ee6a4SAndroid Build Coastguard Worker 
2573*bb4ee6a4SAndroid Build Coastguard Worker     // We open these files before lowering the token, as in the future a stricter policy may
2574*bb4ee6a4SAndroid Build Coastguard Worker     // prevent it.
2575*bb4ee6a4SAndroid Build Coastguard Worker     let dt_overlays = cfg
2576*bb4ee6a4SAndroid Build Coastguard Worker         .device_tree_overlay
2577*bb4ee6a4SAndroid Build Coastguard Worker         .iter()
2578*bb4ee6a4SAndroid Build Coastguard Worker         .map(|o| {
2579*bb4ee6a4SAndroid Build Coastguard Worker             Ok(DtbOverlay {
2580*bb4ee6a4SAndroid Build Coastguard Worker                 file: open_file_or_duplicate(o.path.as_path(), OpenOptions::new().read(true))
2581*bb4ee6a4SAndroid Build Coastguard Worker                     .with_context(|| {
2582*bb4ee6a4SAndroid Build Coastguard Worker                         format!("failed to open device tree overlay {}", o.path.display())
2583*bb4ee6a4SAndroid Build Coastguard Worker                     })?,
2584*bb4ee6a4SAndroid Build Coastguard Worker             })
2585*bb4ee6a4SAndroid Build Coastguard Worker         })
2586*bb4ee6a4SAndroid Build Coastguard Worker         .collect::<Result<Vec<DtbOverlay>>>()?;
2587*bb4ee6a4SAndroid Build Coastguard Worker 
2588*bb4ee6a4SAndroid Build Coastguard Worker     // Lower the token, locking the main process down to a stricter security policy.
2589*bb4ee6a4SAndroid Build Coastguard Worker     //
2590*bb4ee6a4SAndroid Build Coastguard Worker     // WARNING:
2591*bb4ee6a4SAndroid Build Coastguard Worker     //
2592*bb4ee6a4SAndroid Build Coastguard Worker     // Windows system calls can behave in unusual ways if they happen concurrently to the token
2593*bb4ee6a4SAndroid Build Coastguard Worker     // lowering. For example, access denied can happen if Tube pairs are created in another thread
2594*bb4ee6a4SAndroid Build Coastguard Worker     // (b/281108137), and lower_token happens right before the client pipe is connected. Tubes are
2595*bb4ee6a4SAndroid Build Coastguard Worker     // not privileged resources, but can be broken due to the token changing unexpectedly.
2596*bb4ee6a4SAndroid Build Coastguard Worker     //
2597*bb4ee6a4SAndroid Build Coastguard Worker     // We explicitly lower the token here and *then* call run_control to make it clear that any
2598*bb4ee6a4SAndroid Build Coastguard Worker     // resources that require a privileged token should be created on the main thread & passed into
2599*bb4ee6a4SAndroid Build Coastguard Worker     // run_control, to follow the correct order:
2600*bb4ee6a4SAndroid Build Coastguard Worker     // - Privileged resources are created.
2601*bb4ee6a4SAndroid Build Coastguard Worker     // - Token is lowered.
2602*bb4ee6a4SAndroid Build Coastguard Worker     // - Threads are spawned & may create more non-privileged resources (without fear of the token
2603*bb4ee6a4SAndroid Build Coastguard Worker     //   changing at an undefined time).
2604*bb4ee6a4SAndroid Build Coastguard Worker     //
2605*bb4ee6a4SAndroid Build Coastguard Worker     // Recommendation: If you find your code doesnt work in run_control because of the sandbox, you
2606*bb4ee6a4SAndroid Build Coastguard Worker     // should split any resource creation to before this token lowering & pass the resources into
2607*bb4ee6a4SAndroid Build Coastguard Worker     // run_control. Don't move the token lowering somewhere else without considering multi-threaded
2608*bb4ee6a4SAndroid Build Coastguard Worker     // effects.
2609*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "sandbox")]
2610*bb4ee6a4SAndroid Build Coastguard Worker     if sandbox::is_sandbox_target() {
2611*bb4ee6a4SAndroid Build Coastguard Worker         sandbox::TargetServices::get()
2612*bb4ee6a4SAndroid Build Coastguard Worker             .exit_code_from_err("failed to create sandbox")?
2613*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not create sandbox!")
2614*bb4ee6a4SAndroid Build Coastguard Worker             .lower_token();
2615*bb4ee6a4SAndroid Build Coastguard Worker     }
2616*bb4ee6a4SAndroid Build Coastguard Worker 
2617*bb4ee6a4SAndroid Build Coastguard Worker     let virtio_snd_state_device_tube = create_snd_state_tube(&mut control_tubes)?;
2618*bb4ee6a4SAndroid Build Coastguard Worker 
2619*bb4ee6a4SAndroid Build Coastguard Worker     let (virtio_snd_host_mute_tube, virtio_snd_device_mute_tube) = create_snd_mute_tube_pair()?;
2620*bb4ee6a4SAndroid Build Coastguard Worker 
2621*bb4ee6a4SAndroid Build Coastguard Worker     let mut initial_audio_session_states: Vec<InitialAudioSessionState> = Vec::new();
2622*bb4ee6a4SAndroid Build Coastguard Worker 
2623*bb4ee6a4SAndroid Build Coastguard Worker     let pci_devices = create_devices(
2624*bb4ee6a4SAndroid Build Coastguard Worker         &mut cfg,
2625*bb4ee6a4SAndroid Build Coastguard Worker         vm.get_memory(),
2626*bb4ee6a4SAndroid Build Coastguard Worker         &vm_evt_wrtube,
2627*bb4ee6a4SAndroid Build Coastguard Worker         &mut irq_control_tubes,
2628*bb4ee6a4SAndroid Build Coastguard Worker         &mut vm_memory_control_tubes,
2629*bb4ee6a4SAndroid Build Coastguard Worker         &mut control_tubes,
2630*bb4ee6a4SAndroid Build Coastguard Worker         &mut disk_device_tubes,
2631*bb4ee6a4SAndroid Build Coastguard Worker         &mut initial_audio_session_states,
2632*bb4ee6a4SAndroid Build Coastguard Worker         balloon_device_tube,
2633*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "pvclock")]
2634*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device_tube,
2635*bb4ee6a4SAndroid Build Coastguard Worker         dynamic_mapping_device_tube,
2636*bb4ee6a4SAndroid Build Coastguard Worker         /* inflate_tube= */ None,
2637*bb4ee6a4SAndroid Build Coastguard Worker         init_balloon_size,
2638*bb4ee6a4SAndroid Build Coastguard Worker         tsc_state.frequency,
2639*bb4ee6a4SAndroid Build Coastguard Worker         virtio_snd_state_device_tube,
2640*bb4ee6a4SAndroid Build Coastguard Worker         virtio_snd_device_mute_tube,
2641*bb4ee6a4SAndroid Build Coastguard Worker     )?;
2642*bb4ee6a4SAndroid Build Coastguard Worker 
2643*bb4ee6a4SAndroid Build Coastguard Worker     let mut vcpu_ids = Vec::new();
2644*bb4ee6a4SAndroid Build Coastguard Worker 
2645*bb4ee6a4SAndroid Build Coastguard Worker     let (vwmdt_host_tube, vmwdt_device_tube) = Tube::pair().context("failed to create tube")?;
2646*bb4ee6a4SAndroid Build Coastguard Worker     let windows = Arch::build_vm::<V, Vcpu>(
2647*bb4ee6a4SAndroid Build Coastguard Worker         components,
2648*bb4ee6a4SAndroid Build Coastguard Worker         arch_memory_layout,
2649*bb4ee6a4SAndroid Build Coastguard Worker         &vm_evt_wrtube,
2650*bb4ee6a4SAndroid Build Coastguard Worker         &mut sys_allocator,
2651*bb4ee6a4SAndroid Build Coastguard Worker         &cfg.serial_parameters,
2652*bb4ee6a4SAndroid Build Coastguard Worker         None,
2653*bb4ee6a4SAndroid Build Coastguard Worker         (cfg.battery_config.as_ref().map(|t| t.type_), None),
2654*bb4ee6a4SAndroid Build Coastguard Worker         vm,
2655*bb4ee6a4SAndroid Build Coastguard Worker         ramoops_region,
2656*bb4ee6a4SAndroid Build Coastguard Worker         pci_devices,
2657*bb4ee6a4SAndroid Build Coastguard Worker         irq_chip,
2658*bb4ee6a4SAndroid Build Coastguard Worker         &mut vcpu_ids,
2659*bb4ee6a4SAndroid Build Coastguard Worker         cfg.dump_device_tree_blob.clone(),
2660*bb4ee6a4SAndroid Build Coastguard Worker         /* debugcon_jail= */ None,
2661*bb4ee6a4SAndroid Build Coastguard Worker         None,
2662*bb4ee6a4SAndroid Build Coastguard Worker         None,
2663*bb4ee6a4SAndroid Build Coastguard Worker         /* guest_suspended_cvar= */ None,
2664*bb4ee6a4SAndroid Build Coastguard Worker         dt_overlays,
2665*bb4ee6a4SAndroid Build Coastguard Worker         cfg.fdt_position,
2666*bb4ee6a4SAndroid Build Coastguard Worker         cfg.no_pmu,
2667*bb4ee6a4SAndroid Build Coastguard Worker     )
2668*bb4ee6a4SAndroid Build Coastguard Worker     .exit_context(Exit::BuildVm, "the architecture failed to build the vm")?;
2669*bb4ee6a4SAndroid Build Coastguard Worker 
2670*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "stats")]
2671*bb4ee6a4SAndroid Build Coastguard Worker     let stats = if cfg.exit_stats {
2672*bb4ee6a4SAndroid Build Coastguard Worker         Some(Arc::new(Mutex::new(StatisticsCollector::new())))
2673*bb4ee6a4SAndroid Build Coastguard Worker     } else {
2674*bb4ee6a4SAndroid Build Coastguard Worker         None
2675*bb4ee6a4SAndroid Build Coastguard Worker     };
2676*bb4ee6a4SAndroid Build Coastguard Worker 
2677*bb4ee6a4SAndroid Build Coastguard Worker     run_control(
2678*bb4ee6a4SAndroid Build Coastguard Worker         windows,
2679*bb4ee6a4SAndroid Build Coastguard Worker         sys_allocator,
2680*bb4ee6a4SAndroid Build Coastguard Worker         control_tubes,
2681*bb4ee6a4SAndroid Build Coastguard Worker         irq_control_tubes,
2682*bb4ee6a4SAndroid Build Coastguard Worker         vm_memory_control_tubes,
2683*bb4ee6a4SAndroid Build Coastguard Worker         vm_evt_rdtube,
2684*bb4ee6a4SAndroid Build Coastguard Worker         vm_evt_wrtube,
2685*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "gpu")]
2686*bb4ee6a4SAndroid Build Coastguard Worker         gpu_control_tube,
2687*bb4ee6a4SAndroid Build Coastguard Worker         cfg.broker_shutdown_event.take(),
2688*bb4ee6a4SAndroid Build Coastguard Worker         balloon_host_tube,
2689*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "pvclock")]
2690*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_host_tube,
2691*bb4ee6a4SAndroid Build Coastguard Worker         disk_host_tubes,
2692*bb4ee6a4SAndroid Build Coastguard Worker         initial_audio_session_states,
2693*bb4ee6a4SAndroid Build Coastguard Worker         gralloc,
2694*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "stats")]
2695*bb4ee6a4SAndroid Build Coastguard Worker         stats,
2696*bb4ee6a4SAndroid Build Coastguard Worker         cfg.service_pipe_name,
2697*bb4ee6a4SAndroid Build Coastguard Worker         vm_memory_size_mb,
2698*bb4ee6a4SAndroid Build Coastguard Worker         cfg.host_cpu_topology,
2699*bb4ee6a4SAndroid Build Coastguard Worker         tsc_sync_mitigations,
2700*bb4ee6a4SAndroid Build Coastguard Worker         cfg.force_calibrated_tsc_leaf,
2701*bb4ee6a4SAndroid Build Coastguard Worker         product_args,
2702*bb4ee6a4SAndroid Build Coastguard Worker         match virtio_snd_host_mute_tube {
2703*bb4ee6a4SAndroid Build Coastguard Worker             Some(virtio_snd_host_mute_tube) => vec![virtio_snd_host_mute_tube],
2704*bb4ee6a4SAndroid Build Coastguard Worker             None => vec![],
2705*bb4ee6a4SAndroid Build Coastguard Worker         },
2706*bb4ee6a4SAndroid Build Coastguard Worker         cfg.restore_path,
2707*bb4ee6a4SAndroid Build Coastguard Worker         cfg.socket_path,
2708*bb4ee6a4SAndroid Build Coastguard Worker         cfg.force_s2idle,
2709*bb4ee6a4SAndroid Build Coastguard Worker         cfg.suspended,
2710*bb4ee6a4SAndroid Build Coastguard Worker     )
2711*bb4ee6a4SAndroid Build Coastguard Worker }
2712*bb4ee6a4SAndroid Build Coastguard Worker 
2713*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
2714*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
2715*bb4ee6a4SAndroid Build Coastguard Worker     use tempfile::TempDir;
2716*bb4ee6a4SAndroid Build Coastguard Worker 
2717*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
2718*bb4ee6a4SAndroid Build Coastguard Worker 
2719*bb4ee6a4SAndroid Build Coastguard Worker     fn create_config(test_dir: &TempDir) -> Config {
2720*bb4ee6a4SAndroid Build Coastguard Worker         let mut config = Config::default();
2721*bb4ee6a4SAndroid Build Coastguard Worker 
2722*bb4ee6a4SAndroid Build Coastguard Worker         let dummy_kernel_path = test_dir.path().join("dummy_kernel.txt");
2723*bb4ee6a4SAndroid Build Coastguard Worker         OpenOptions::new()
2724*bb4ee6a4SAndroid Build Coastguard Worker             .create_new(true)
2725*bb4ee6a4SAndroid Build Coastguard Worker             .write(true)
2726*bb4ee6a4SAndroid Build Coastguard Worker             .open(&dummy_kernel_path)
2727*bb4ee6a4SAndroid Build Coastguard Worker             .expect("Could not open file!");
2728*bb4ee6a4SAndroid Build Coastguard Worker         config.executable_path = Some(Executable::Kernel(dummy_kernel_path));
2729*bb4ee6a4SAndroid Build Coastguard Worker 
2730*bb4ee6a4SAndroid Build Coastguard Worker         config
2731*bb4ee6a4SAndroid Build Coastguard Worker     }
2732*bb4ee6a4SAndroid Build Coastguard Worker 
2733*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
2734*bb4ee6a4SAndroid Build Coastguard Worker     #[should_panic(expected = "Did not receive a bios or kernel")]
2735*bb4ee6a4SAndroid Build Coastguard Worker     fn setup_vm_components_panics_when_no_kernel_provided() {
2736*bb4ee6a4SAndroid Build Coastguard Worker         let mut config =
2737*bb4ee6a4SAndroid Build Coastguard Worker             create_config(&TempDir::new().expect("Could not create temporary directory!"));
2738*bb4ee6a4SAndroid Build Coastguard Worker         config.executable_path = None;
2739*bb4ee6a4SAndroid Build Coastguard Worker         let _ = setup_vm_components(&config);
2740*bb4ee6a4SAndroid Build Coastguard Worker     }
2741*bb4ee6a4SAndroid Build Coastguard Worker 
2742*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
2743*bb4ee6a4SAndroid Build Coastguard Worker     fn setup_vm_components_stores_memory_in_bytes() {
2744*bb4ee6a4SAndroid Build Coastguard Worker         let tempdir = TempDir::new().expect("Could not create temporary directory!");
2745*bb4ee6a4SAndroid Build Coastguard Worker         let mut config = create_config(&tempdir);
2746*bb4ee6a4SAndroid Build Coastguard Worker         config.memory = Some(1);
2747*bb4ee6a4SAndroid Build Coastguard Worker         let vm_components = setup_vm_components(&config).expect("failed to setup vm components");
2748*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(vm_components.memory_size, 1024 * 1024);
2749*bb4ee6a4SAndroid Build Coastguard Worker     }
2750*bb4ee6a4SAndroid Build Coastguard Worker 
2751*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
2752*bb4ee6a4SAndroid Build Coastguard Worker     fn setup_vm_components_fails_when_memory_too_large() {
2753*bb4ee6a4SAndroid Build Coastguard Worker         let tempdir = TempDir::new().expect("Could not create temporary directory!");
2754*bb4ee6a4SAndroid Build Coastguard Worker         let mut config = create_config(&tempdir);
2755*bb4ee6a4SAndroid Build Coastguard Worker         // One mb more than a u64 can hold in bytes
2756*bb4ee6a4SAndroid Build Coastguard Worker         config.memory = Some((u64::MAX / 1024 / 1024) + 1);
2757*bb4ee6a4SAndroid Build Coastguard Worker         setup_vm_components(&config).err().expect("expected error");
2758*bb4ee6a4SAndroid Build Coastguard Worker     }
2759*bb4ee6a4SAndroid Build Coastguard Worker }
2760