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