• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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