1 // Copyright 2022 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::io; 6 use std::io::Write; 7 8 use base::error; 9 #[cfg(windows)] 10 use base::named_pipes; 11 use base::Event; 12 use base::FileSync; 13 use base::RawDescriptor; 14 use base::Result; 15 use hypervisor::ProtectionType; 16 use snapshot::AnySnapshot; 17 18 use crate::pci::CrosvmDeviceId; 19 use crate::serial_device::SerialInput; 20 use crate::serial_device::SerialOptions; 21 use crate::BusAccessInfo; 22 use crate::BusDevice; 23 use crate::DeviceId; 24 use crate::SerialDevice; 25 use crate::Suspendable; 26 27 const BOCHS_DEBUGCON_READBACK: u8 = 0xe9; 28 29 pub struct Debugcon { 30 out: Option<Box<dyn io::Write + Send>>, 31 } 32 33 impl SerialDevice for Debugcon { new( _protection_type: ProtectionType, _interrupt_evt: Event, _input: Option<Box<dyn SerialInput>>, out: Option<Box<dyn io::Write + Send>>, _sync: Option<Box<dyn FileSync + Send>>, _options: SerialOptions, _keep_rds: Vec<RawDescriptor>, ) -> Debugcon34 fn new( 35 _protection_type: ProtectionType, 36 _interrupt_evt: Event, 37 _input: Option<Box<dyn SerialInput>>, 38 out: Option<Box<dyn io::Write + Send>>, 39 _sync: Option<Box<dyn FileSync + Send>>, 40 _options: SerialOptions, 41 _keep_rds: Vec<RawDescriptor>, 42 ) -> Debugcon { 43 Debugcon { out } 44 } 45 46 #[cfg(windows)] new_with_pipe( _protection_type: ProtectionType, _interrupt_evt: Event, _pipe_in: named_pipes::PipeConnection, _pipe_out: named_pipes::PipeConnection, _options: SerialOptions, _keep_rds: Vec<RawDescriptor>, ) -> Debugcon47 fn new_with_pipe( 48 _protection_type: ProtectionType, 49 _interrupt_evt: Event, 50 _pipe_in: named_pipes::PipeConnection, 51 _pipe_out: named_pipes::PipeConnection, 52 _options: SerialOptions, 53 _keep_rds: Vec<RawDescriptor>, 54 ) -> Debugcon { 55 unimplemented!("new_with_pipe unimplemented for Debugcon"); 56 } 57 } 58 59 impl BusDevice for Debugcon { device_id(&self) -> DeviceId60 fn device_id(&self) -> DeviceId { 61 CrosvmDeviceId::DebugConsole.into() 62 } 63 debug_label(&self) -> String64 fn debug_label(&self) -> String { 65 "debugcon".to_owned() 66 } 67 write(&mut self, _info: BusAccessInfo, data: &[u8])68 fn write(&mut self, _info: BusAccessInfo, data: &[u8]) { 69 if data.len() != 1 { 70 return; 71 } 72 if let Err(e) = self.handle_write(data) { 73 error!("debugcon failed write: {}", e); 74 } 75 } 76 read(&mut self, _info: BusAccessInfo, data: &mut [u8])77 fn read(&mut self, _info: BusAccessInfo, data: &mut [u8]) { 78 if data.len() != 1 { 79 return; 80 } 81 data[0] = BOCHS_DEBUGCON_READBACK; 82 } 83 } 84 85 impl Debugcon { handle_write(&mut self, data: &[u8]) -> Result<()>86 fn handle_write(&mut self, data: &[u8]) -> Result<()> { 87 if let Some(out) = self.out.as_mut() { 88 out.write_all(data)?; 89 out.flush()?; 90 } 91 Ok(()) 92 } 93 } 94 95 impl Suspendable for Debugcon { sleep(&mut self) -> anyhow::Result<()>96 fn sleep(&mut self) -> anyhow::Result<()> { 97 Ok(()) 98 } 99 wake(&mut self) -> anyhow::Result<()>100 fn wake(&mut self) -> anyhow::Result<()> { 101 Ok(()) 102 } 103 snapshot(&mut self) -> anyhow::Result<AnySnapshot>104 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> { 105 AnySnapshot::to_any(()) 106 } 107 restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>108 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> { 109 let () = AnySnapshot::from_any(data)?; 110 Ok(()) 111 } 112 } 113 114 #[cfg(test)] 115 mod tests { 116 use std::io; 117 use std::sync::Arc; 118 119 use sync::Mutex; 120 121 use super::*; 122 123 const ADDR: BusAccessInfo = BusAccessInfo { 124 offset: 0, 125 address: 0, 126 id: 0, 127 }; 128 129 // XXX(gerow): copied from devices/src/serial.rs 130 #[derive(Clone)] 131 struct SharedBuffer { 132 buf: Arc<Mutex<Vec<u8>>>, 133 } 134 135 impl SharedBuffer { new() -> SharedBuffer136 fn new() -> SharedBuffer { 137 SharedBuffer { 138 buf: Arc::new(Mutex::new(Vec::new())), 139 } 140 } 141 } 142 143 impl io::Write for SharedBuffer { write(&mut self, buf: &[u8]) -> io::Result<usize>144 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 145 self.buf.lock().write(buf) 146 } flush(&mut self) -> io::Result<()>147 fn flush(&mut self) -> io::Result<()> { 148 self.buf.lock().flush() 149 } 150 } 151 152 #[test] write()153 fn write() { 154 let debugcon_out = SharedBuffer::new(); 155 let mut debugcon = Debugcon::new( 156 ProtectionType::Unprotected, 157 Event::new().unwrap(), 158 None, 159 Some(Box::new(debugcon_out.clone())), 160 None, 161 Default::default(), 162 Vec::new(), 163 ); 164 165 debugcon.write(ADDR, b"a"); 166 debugcon.write(ADDR, b"b"); 167 debugcon.write(ADDR, b"c"); 168 assert_eq!(debugcon_out.buf.lock().as_slice(), b"abc"); 169 } 170 171 #[test] read()172 fn read() { 173 let mut debugcon = Debugcon::new( 174 ProtectionType::Unprotected, 175 Event::new().unwrap(), 176 None, 177 None, 178 None, 179 Default::default(), 180 Vec::new(), 181 ); 182 183 let mut data = [0u8; 1]; 184 debugcon.read(ADDR, &mut data[..]); 185 assert_eq!(data[0], 0xe9); 186 } 187 } 188