xref: /aosp_15_r20/external/crosvm/devices/src/virtio/console/device.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! virtio-console and vhost-user-console device shared backend implementation
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
8*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le32;
9*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::ProtectionType;
10*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
11*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
12*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
13*bb4ee6a4SAndroid Build Coastguard Worker 
14*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::base_features;
15*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::console::port::ConsolePort;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::console::port::ConsolePortSnapshot;
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::console::worker::WorkerHandle;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::console::worker::WorkerPort;
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::copy_config;
20*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::device_constants::console::virtio_console_config;
21*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::device_constants::console::VIRTIO_CONSOLE_F_MULTIPORT;
22*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Interrupt;
23*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Queue;
24*bb4ee6a4SAndroid Build Coastguard Worker 
25*bb4ee6a4SAndroid Build Coastguard Worker pub struct ConsoleDevice {
26*bb4ee6a4SAndroid Build Coastguard Worker     avail_features: u64,
27*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) ports: Vec<ConsolePort>,
28*bb4ee6a4SAndroid Build Coastguard Worker     worker: Option<WorkerHandle>,
29*bb4ee6a4SAndroid Build Coastguard Worker }
30*bb4ee6a4SAndroid Build Coastguard Worker 
31*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)]
32*bb4ee6a4SAndroid Build Coastguard Worker pub struct ConsoleSnapshot {
33*bb4ee6a4SAndroid Build Coastguard Worker     avail_features: u64,
34*bb4ee6a4SAndroid Build Coastguard Worker     ports: Vec<ConsolePortSnapshot>,
35*bb4ee6a4SAndroid Build Coastguard Worker }
36*bb4ee6a4SAndroid Build Coastguard Worker 
37*bb4ee6a4SAndroid Build Coastguard Worker impl ConsoleDevice {
38*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a console device that does not support the multiport feature.
new_single_port(protection_type: ProtectionType, port: ConsolePort) -> ConsoleDevice39*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_single_port(protection_type: ProtectionType, port: ConsolePort) -> ConsoleDevice {
40*bb4ee6a4SAndroid Build Coastguard Worker         ConsoleDevice {
41*bb4ee6a4SAndroid Build Coastguard Worker             avail_features: base_features(protection_type),
42*bb4ee6a4SAndroid Build Coastguard Worker             ports: vec![port],
43*bb4ee6a4SAndroid Build Coastguard Worker             worker: None,
44*bb4ee6a4SAndroid Build Coastguard Worker         }
45*bb4ee6a4SAndroid Build Coastguard Worker     }
46*bb4ee6a4SAndroid Build Coastguard Worker 
47*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a console device with the multiport feature enabled.
new_multi_port( protection_type: ProtectionType, ports: Vec<ConsolePort>, ) -> ConsoleDevice48*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_multi_port(
49*bb4ee6a4SAndroid Build Coastguard Worker         protection_type: ProtectionType,
50*bb4ee6a4SAndroid Build Coastguard Worker         ports: Vec<ConsolePort>,
51*bb4ee6a4SAndroid Build Coastguard Worker     ) -> ConsoleDevice {
52*bb4ee6a4SAndroid Build Coastguard Worker         // Port 0 must always exist.
53*bb4ee6a4SAndroid Build Coastguard Worker         assert!(!ports.is_empty());
54*bb4ee6a4SAndroid Build Coastguard Worker 
55*bb4ee6a4SAndroid Build Coastguard Worker         let avail_features = base_features(protection_type) | (1 << VIRTIO_CONSOLE_F_MULTIPORT);
56*bb4ee6a4SAndroid Build Coastguard Worker 
57*bb4ee6a4SAndroid Build Coastguard Worker         ConsoleDevice {
58*bb4ee6a4SAndroid Build Coastguard Worker             avail_features,
59*bb4ee6a4SAndroid Build Coastguard Worker             ports,
60*bb4ee6a4SAndroid Build Coastguard Worker             worker: None,
61*bb4ee6a4SAndroid Build Coastguard Worker         }
62*bb4ee6a4SAndroid Build Coastguard Worker     }
63*bb4ee6a4SAndroid Build Coastguard Worker 
features(&self) -> u6464*bb4ee6a4SAndroid Build Coastguard Worker     pub fn features(&self) -> u64 {
65*bb4ee6a4SAndroid Build Coastguard Worker         self.avail_features
66*bb4ee6a4SAndroid Build Coastguard Worker     }
67*bb4ee6a4SAndroid Build Coastguard Worker 
max_ports(&self) -> usize68*bb4ee6a4SAndroid Build Coastguard Worker     pub fn max_ports(&self) -> usize {
69*bb4ee6a4SAndroid Build Coastguard Worker         self.ports.len()
70*bb4ee6a4SAndroid Build Coastguard Worker     }
71*bb4ee6a4SAndroid Build Coastguard Worker 
72*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the maximum number of queues supported by this device.
max_queues(&self) -> usize73*bb4ee6a4SAndroid Build Coastguard Worker     pub fn max_queues(&self) -> usize {
74*bb4ee6a4SAndroid Build Coastguard Worker         // The port 0 receive and transmit queues always exist;
75*bb4ee6a4SAndroid Build Coastguard Worker         // other queues only exist if VIRTIO_CONSOLE_F_MULTIPORT is set.
76*bb4ee6a4SAndroid Build Coastguard Worker         let num_queues = self.ports.len().max(1);
77*bb4ee6a4SAndroid Build Coastguard Worker         if self.avail_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT) != 0 {
78*bb4ee6a4SAndroid Build Coastguard Worker             // Each port has two queues (tx & rx), plus 2 for control receiveq and transmitq.
79*bb4ee6a4SAndroid Build Coastguard Worker             num_queues * 2 + 2
80*bb4ee6a4SAndroid Build Coastguard Worker         } else {
81*bb4ee6a4SAndroid Build Coastguard Worker             // port0 receiveq + transmitq
82*bb4ee6a4SAndroid Build Coastguard Worker             2
83*bb4ee6a4SAndroid Build Coastguard Worker         }
84*bb4ee6a4SAndroid Build Coastguard Worker     }
85*bb4ee6a4SAndroid Build Coastguard Worker 
read_config(&self, offset: u64, data: &mut [u8])86*bb4ee6a4SAndroid Build Coastguard Worker     pub fn read_config(&self, offset: u64, data: &mut [u8]) {
87*bb4ee6a4SAndroid Build Coastguard Worker         let max_nr_ports = self.max_ports();
88*bb4ee6a4SAndroid Build Coastguard Worker         let config = virtio_console_config {
89*bb4ee6a4SAndroid Build Coastguard Worker             max_nr_ports: Le32::from(max_nr_ports as u32),
90*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
91*bb4ee6a4SAndroid Build Coastguard Worker         };
92*bb4ee6a4SAndroid Build Coastguard Worker         copy_config(data, 0, config.as_bytes(), offset);
93*bb4ee6a4SAndroid Build Coastguard Worker     }
94*bb4ee6a4SAndroid Build Coastguard Worker 
keep_rds(&self) -> Vec<RawDescriptor>95*bb4ee6a4SAndroid Build Coastguard Worker     pub fn keep_rds(&self) -> Vec<RawDescriptor> {
96*bb4ee6a4SAndroid Build Coastguard Worker         self.ports.iter().flat_map(ConsolePort::keep_rds).collect()
97*bb4ee6a4SAndroid Build Coastguard Worker     }
98*bb4ee6a4SAndroid Build Coastguard Worker 
ensure_worker_started(&mut self, interrupt: Interrupt) -> &mut WorkerHandle99*bb4ee6a4SAndroid Build Coastguard Worker     fn ensure_worker_started(&mut self, interrupt: Interrupt) -> &mut WorkerHandle {
100*bb4ee6a4SAndroid Build Coastguard Worker         self.worker.get_or_insert_with(|| {
101*bb4ee6a4SAndroid Build Coastguard Worker             let ports = self
102*bb4ee6a4SAndroid Build Coastguard Worker                 .ports
103*bb4ee6a4SAndroid Build Coastguard Worker                 .iter_mut()
104*bb4ee6a4SAndroid Build Coastguard Worker                 .map(WorkerPort::from_console_port)
105*bb4ee6a4SAndroid Build Coastguard Worker                 .collect();
106*bb4ee6a4SAndroid Build Coastguard Worker             WorkerHandle::new(interrupt, ports).expect("failed to create console worker")
107*bb4ee6a4SAndroid Build Coastguard Worker         })
108*bb4ee6a4SAndroid Build Coastguard Worker     }
109*bb4ee6a4SAndroid Build Coastguard Worker 
ensure_worker_stopped(&mut self)110*bb4ee6a4SAndroid Build Coastguard Worker     fn ensure_worker_stopped(&mut self) {
111*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(worker) = self.worker.take() {
112*bb4ee6a4SAndroid Build Coastguard Worker             let ports = worker.stop();
113*bb4ee6a4SAndroid Build Coastguard Worker             for (worker_port, port) in ports.into_iter().zip(self.ports.iter_mut()) {
114*bb4ee6a4SAndroid Build Coastguard Worker                 worker_port.into_console_port(port);
115*bb4ee6a4SAndroid Build Coastguard Worker             }
116*bb4ee6a4SAndroid Build Coastguard Worker         }
117*bb4ee6a4SAndroid Build Coastguard Worker     }
118*bb4ee6a4SAndroid Build Coastguard Worker 
start_queue(&mut self, idx: usize, queue: Queue) -> anyhow::Result<()>119*bb4ee6a4SAndroid Build Coastguard Worker     pub fn start_queue(&mut self, idx: usize, queue: Queue) -> anyhow::Result<()> {
120*bb4ee6a4SAndroid Build Coastguard Worker         let worker = self.ensure_worker_started(queue.interrupt().clone());
121*bb4ee6a4SAndroid Build Coastguard Worker         worker.start_queue(idx, queue)
122*bb4ee6a4SAndroid Build Coastguard Worker     }
123*bb4ee6a4SAndroid Build Coastguard Worker 
stop_queue(&mut self, idx: usize) -> anyhow::Result<Option<Queue>>124*bb4ee6a4SAndroid Build Coastguard Worker     pub fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Option<Queue>> {
125*bb4ee6a4SAndroid Build Coastguard Worker         match self.worker.as_mut() {
126*bb4ee6a4SAndroid Build Coastguard Worker             Some(worker) => worker.stop_queue(idx),
127*bb4ee6a4SAndroid Build Coastguard Worker             None => Ok(None),
128*bb4ee6a4SAndroid Build Coastguard Worker         }
129*bb4ee6a4SAndroid Build Coastguard Worker     }
130*bb4ee6a4SAndroid Build Coastguard Worker 
reset(&mut self) -> anyhow::Result<()>131*bb4ee6a4SAndroid Build Coastguard Worker     pub fn reset(&mut self) -> anyhow::Result<()> {
132*bb4ee6a4SAndroid Build Coastguard Worker         for idx in 0..self.max_queues() {
133*bb4ee6a4SAndroid Build Coastguard Worker             let _ = self.stop_queue(idx);
134*bb4ee6a4SAndroid Build Coastguard Worker         }
135*bb4ee6a4SAndroid Build Coastguard Worker         self.ensure_worker_stopped();
136*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
137*bb4ee6a4SAndroid Build Coastguard Worker     }
138*bb4ee6a4SAndroid Build Coastguard Worker 
start_input_threads(&mut self)139*bb4ee6a4SAndroid Build Coastguard Worker     pub fn start_input_threads(&mut self) {
140*bb4ee6a4SAndroid Build Coastguard Worker         for port in self.ports.iter_mut() {
141*bb4ee6a4SAndroid Build Coastguard Worker             port.start_input_thread();
142*bb4ee6a4SAndroid Build Coastguard Worker         }
143*bb4ee6a4SAndroid Build Coastguard Worker     }
144*bb4ee6a4SAndroid Build Coastguard Worker 
stop_input_threads(&mut self)145*bb4ee6a4SAndroid Build Coastguard Worker     pub fn stop_input_threads(&mut self) {
146*bb4ee6a4SAndroid Build Coastguard Worker         for port in self.ports.iter_mut() {
147*bb4ee6a4SAndroid Build Coastguard Worker             port.stop_input_thread();
148*bb4ee6a4SAndroid Build Coastguard Worker         }
149*bb4ee6a4SAndroid Build Coastguard Worker     }
150*bb4ee6a4SAndroid Build Coastguard Worker 
snapshot(&mut self) -> anyhow::Result<ConsoleSnapshot>151*bb4ee6a4SAndroid Build Coastguard Worker     pub fn snapshot(&mut self) -> anyhow::Result<ConsoleSnapshot> {
152*bb4ee6a4SAndroid Build Coastguard Worker         let mut ports = Vec::new();
153*bb4ee6a4SAndroid Build Coastguard Worker         for port in &mut self.ports {
154*bb4ee6a4SAndroid Build Coastguard Worker             ports.push(port.snapshot());
155*bb4ee6a4SAndroid Build Coastguard Worker         }
156*bb4ee6a4SAndroid Build Coastguard Worker 
157*bb4ee6a4SAndroid Build Coastguard Worker         Ok(ConsoleSnapshot {
158*bb4ee6a4SAndroid Build Coastguard Worker             avail_features: self.avail_features,
159*bb4ee6a4SAndroid Build Coastguard Worker             ports,
160*bb4ee6a4SAndroid Build Coastguard Worker         })
161*bb4ee6a4SAndroid Build Coastguard Worker     }
162*bb4ee6a4SAndroid Build Coastguard Worker 
restore(&mut self, snap: &ConsoleSnapshot) -> anyhow::Result<()>163*bb4ee6a4SAndroid Build Coastguard Worker     pub fn restore(&mut self, snap: &ConsoleSnapshot) -> anyhow::Result<()> {
164*bb4ee6a4SAndroid Build Coastguard Worker         anyhow::ensure!(
165*bb4ee6a4SAndroid Build Coastguard Worker             self.avail_features == snap.avail_features,
166*bb4ee6a4SAndroid Build Coastguard Worker             "Virtio console incorrect features for restore: Expected: {}, Actual: {}",
167*bb4ee6a4SAndroid Build Coastguard Worker             self.avail_features,
168*bb4ee6a4SAndroid Build Coastguard Worker             snap.avail_features,
169*bb4ee6a4SAndroid Build Coastguard Worker         );
170*bb4ee6a4SAndroid Build Coastguard Worker 
171*bb4ee6a4SAndroid Build Coastguard Worker         for (port, port_snap) in self.ports.iter_mut().zip(snap.ports.iter()) {
172*bb4ee6a4SAndroid Build Coastguard Worker             port.restore(port_snap);
173*bb4ee6a4SAndroid Build Coastguard Worker         }
174*bb4ee6a4SAndroid Build Coastguard Worker 
175*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
176*bb4ee6a4SAndroid Build Coastguard Worker     }
177*bb4ee6a4SAndroid Build Coastguard Worker }
178