xref: /aosp_15_r20/external/crosvm/devices/src/debugcon.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
17 use crate::pci::CrosvmDeviceId;
18 use crate::serial_device::SerialInput;
19 use crate::serial_device::SerialOptions;
20 use crate::BusAccessInfo;
21 use crate::BusDevice;
22 use crate::DeviceId;
23 use crate::SerialDevice;
24 use crate::Suspendable;
25 
26 const BOCHS_DEBUGCON_READBACK: u8 = 0xe9;
27 
28 pub struct Debugcon {
29     out: Option<Box<dyn io::Write + Send>>,
30 }
31 
32 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>, ) -> Debugcon33     fn new(
34         _protection_type: ProtectionType,
35         _interrupt_evt: Event,
36         _input: Option<Box<dyn SerialInput>>,
37         out: Option<Box<dyn io::Write + Send>>,
38         _sync: Option<Box<dyn FileSync + Send>>,
39         _options: SerialOptions,
40         _keep_rds: Vec<RawDescriptor>,
41     ) -> Debugcon {
42         Debugcon { out }
43     }
44 
45     #[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>, ) -> Debugcon46     fn new_with_pipe(
47         _protection_type: ProtectionType,
48         _interrupt_evt: Event,
49         _pipe_in: named_pipes::PipeConnection,
50         _pipe_out: named_pipes::PipeConnection,
51         _options: SerialOptions,
52         _keep_rds: Vec<RawDescriptor>,
53     ) -> Debugcon {
54         unimplemented!("new_with_pipe unimplemented for Debugcon");
55     }
56 }
57 
58 impl BusDevice for Debugcon {
device_id(&self) -> DeviceId59     fn device_id(&self) -> DeviceId {
60         CrosvmDeviceId::DebugConsole.into()
61     }
62 
debug_label(&self) -> String63     fn debug_label(&self) -> String {
64         "debugcon".to_owned()
65     }
66 
write(&mut self, _info: BusAccessInfo, data: &[u8])67     fn write(&mut self, _info: BusAccessInfo, data: &[u8]) {
68         if data.len() != 1 {
69             return;
70         }
71         if let Err(e) = self.handle_write(data) {
72             error!("debugcon failed write: {}", e);
73         }
74     }
75 
read(&mut self, _info: BusAccessInfo, data: &mut [u8])76     fn read(&mut self, _info: BusAccessInfo, data: &mut [u8]) {
77         if data.len() != 1 {
78             return;
79         }
80         data[0] = BOCHS_DEBUGCON_READBACK;
81     }
82 }
83 
84 impl Debugcon {
handle_write(&mut self, data: &[u8]) -> Result<()>85     fn handle_write(&mut self, data: &[u8]) -> Result<()> {
86         if let Some(out) = self.out.as_mut() {
87             out.write_all(data)?;
88             out.flush()?;
89         }
90         Ok(())
91     }
92 }
93 
94 impl Suspendable for Debugcon {
sleep(&mut self) -> anyhow::Result<()>95     fn sleep(&mut self) -> anyhow::Result<()> {
96         Ok(())
97     }
98 
wake(&mut self) -> anyhow::Result<()>99     fn wake(&mut self) -> anyhow::Result<()> {
100         Ok(())
101     }
102 
snapshot(&mut self) -> anyhow::Result<serde_json::Value>103     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
104         Ok(serde_json::Value::Null)
105     }
106 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>107     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
108         anyhow::ensure!(
109             data == serde_json::Value::Null,
110             "unexpected snapshot data: should be null, got {}",
111             data,
112         );
113         Ok(())
114     }
115 }
116 
117 #[cfg(test)]
118 mod tests {
119     use std::io;
120     use std::sync::Arc;
121 
122     use sync::Mutex;
123 
124     use super::*;
125 
126     const ADDR: BusAccessInfo = BusAccessInfo {
127         offset: 0,
128         address: 0,
129         id: 0,
130     };
131 
132     // XXX(gerow): copied from devices/src/serial.rs
133     #[derive(Clone)]
134     struct SharedBuffer {
135         buf: Arc<Mutex<Vec<u8>>>,
136     }
137 
138     impl SharedBuffer {
new() -> SharedBuffer139         fn new() -> SharedBuffer {
140             SharedBuffer {
141                 buf: Arc::new(Mutex::new(Vec::new())),
142             }
143         }
144     }
145 
146     impl io::Write for SharedBuffer {
write(&mut self, buf: &[u8]) -> io::Result<usize>147         fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
148             self.buf.lock().write(buf)
149         }
flush(&mut self) -> io::Result<()>150         fn flush(&mut self) -> io::Result<()> {
151             self.buf.lock().flush()
152         }
153     }
154 
155     #[test]
write()156     fn write() {
157         let debugcon_out = SharedBuffer::new();
158         let mut debugcon = Debugcon::new(
159             ProtectionType::Unprotected,
160             Event::new().unwrap(),
161             None,
162             Some(Box::new(debugcon_out.clone())),
163             None,
164             Default::default(),
165             Vec::new(),
166         );
167 
168         debugcon.write(ADDR, b"a");
169         debugcon.write(ADDR, b"b");
170         debugcon.write(ADDR, b"c");
171         assert_eq!(debugcon_out.buf.lock().as_slice(), b"abc");
172     }
173 
174     #[test]
read()175     fn read() {
176         let mut debugcon = Debugcon::new(
177             ProtectionType::Unprotected,
178             Event::new().unwrap(),
179             None,
180             None,
181             None,
182             Default::default(),
183             Vec::new(),
184         );
185 
186         let mut data = [0u8; 1];
187         debugcon.read(ADDR, &mut data[..]);
188         assert_eq!(data[0], 0xe9);
189     }
190 }
191