1use std::io;
6use std::io::Write;
7
8use base::error;
9#[cfg(windows)]
10use base::named_pipes;
11use base::Event;
12use base::FileSync;
13use base::RawDescriptor;
14use base::Result;
15use hypervisor::ProtectionType;
16use snapshot::AnySnapshot;
17
18use crate::pci::CrosvmDeviceId;
19use crate::serial_device::SerialInput;
20use crate::serial_device::SerialOptions;
21use crate::BusAccessInfo;
22use crate::BusDevice;
23use crate::DeviceId;
24use crate::SerialDevice;
25use crate::Suspendable;
26
27const BOCHS_DEBUGCON_READBACK: u8 = 0xe9;
28
29pub struct Debugcon {
30 out: Option<Box<dyn io::Write + Send>>,
31}
32
33impl SerialDevice for Debugcon {
34 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)]
47 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
59impl BusDevice for Debugcon {
60 fn device_id(&self) -> DeviceId {
61 CrosvmDeviceId::DebugConsole.into()
62 }
63
64 fn debug_label(&self) -> String {
65 "debugcon".to_owned()
66 }
67
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
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
85impl Debugcon {
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
95impl Suspendable for Debugcon {
96 fn sleep(&mut self) -> anyhow::Result<()> {
97 Ok(())
98 }
99
100 fn wake(&mut self) -> anyhow::Result<()> {
101 Ok(())
102 }
103
104 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
105 AnySnapshot::to_any(())
106 }
107
108 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
109 let () = AnySnapshot::from_any(data)?;
110 Ok(())
111 }
112}
113
114#[cfg(test)]
115mod 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 #[derive(Clone)]
131 struct SharedBuffer {
132 buf: Arc<Mutex<Vec<u8>>>,
133 }
134
135 impl SharedBuffer {
136 fn new() -> SharedBuffer {
137 SharedBuffer {
138 buf: Arc::new(Mutex::new(Vec::new())),
139 }
140 }
141 }
142
143 impl io::Write for SharedBuffer {
144 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
145 self.buf.lock().write(buf)
146 }
147 fn flush(&mut self) -> io::Result<()> {
148 self.buf.lock().flush()
149 }
150 }
151
152 #[test]
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]
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}