devices/
debugcon.rs

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
5use 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    // 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 {
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}