1#![forbid(unsafe_code)]
11
12pub mod resolver;
13
14use chipset_device::ChipsetDevice;
15use chipset_device::io::IoError;
16use chipset_device::io::IoResult;
17use chipset_device::pio::PortIoIntercept;
18use chipset_device::poll_device::PollDevice;
19use futures::AsyncWrite;
20use inspect::InspectMut;
21use serial_core::SerialIo;
22use std::collections::VecDeque;
23use std::io::ErrorKind;
24use std::ops::RangeInclusive;
25use std::pin::Pin;
26use std::task::Context;
27use std::task::Poll;
28use std::task::Waker;
29use std::task::ready;
30use vmcore::device_state::ChangeDeviceState;
31
32const TX_BUFFER_MAX: usize = 1024 * 1024; #[derive(InspectMut)]
39pub struct SerialDebugcon {
40 io_port: u16,
42 #[inspect(skip)]
43 io_region: (&'static str, RangeInclusive<u16>),
44
45 #[inspect(mut)]
47 io: Box<dyn SerialIo>,
48
49 #[inspect(with = "VecDeque::len")]
51 tx_buffer: VecDeque<u8>,
52 #[inspect(skip)]
53 tx_waker: Option<Waker>,
54}
55
56impl SerialDebugcon {
57 pub fn new(port: u16, io: Box<dyn SerialIo>) -> Self {
59 Self {
60 io_port: port,
61 io_region: ("debugcon", port..=port),
62 io,
63 tx_buffer: VecDeque::new(),
64 tx_waker: None,
65 }
66 }
67
68 fn sync(&mut self) {
70 if !self.tx_buffer.is_empty() {
72 if let Some(waker) = self.tx_waker.take() {
73 waker.wake();
74 }
75 }
76 }
77
78 fn poll_tx(&mut self, cx: &mut Context<'_>) -> Poll<()> {
79 while !self.tx_buffer.is_empty() {
80 let (buf, _) = self.tx_buffer.as_slices();
81 match ready!(Pin::new(&mut self.io).poll_write(cx, buf)) {
82 Ok(n) => {
83 assert_ne!(n, 0);
84 self.tx_buffer.drain(..n);
85 }
86 Err(err) if err.kind() == ErrorKind::BrokenPipe => {
87 tracing::info!("debugcon output broken pipe");
88 }
89 Err(err) => {
90 tracelimit::error_ratelimited!(
91 len = buf.len(),
92 error = &err as &dyn std::error::Error,
93 "debugcon write failed, dropping data"
94 );
95 self.tx_buffer.drain(..buf.len());
96 }
97 }
98 }
99 self.tx_waker = Some(cx.waker().clone());
101 Poll::Pending
102 }
103}
104
105impl ChangeDeviceState for SerialDebugcon {
106 fn start(&mut self) {}
107
108 async fn stop(&mut self) {}
109
110 async fn reset(&mut self) {
111 self.tx_buffer.clear();
112 }
113}
114
115impl ChipsetDevice for SerialDebugcon {
116 fn supports_pio(&mut self) -> Option<&mut dyn PortIoIntercept> {
117 Some(self)
118 }
119
120 fn supports_poll_device(&mut self) -> Option<&mut dyn PollDevice> {
121 Some(self)
122 }
123}
124
125impl PollDevice for SerialDebugcon {
126 fn poll_device(&mut self, cx: &mut Context<'_>) {
127 let _ = self.poll_tx(cx);
128 self.sync();
129 }
130}
131
132impl PortIoIntercept for SerialDebugcon {
133 fn io_read(&mut self, io_port: u16, data: &mut [u8]) -> IoResult {
134 if io_port != self.io_port {
135 return IoResult::Err(IoError::InvalidRegister);
136 }
137
138 if data.len() != 1 {
139 return IoResult::Err(IoError::InvalidAccessSize);
140 }
141
142 data[0] = 0xe9;
146
147 IoResult::Ok
148 }
149
150 fn io_write(&mut self, io_port: u16, data: &[u8]) -> IoResult {
151 if io_port != self.io_port {
152 return IoResult::Err(IoError::InvalidRegister);
153 }
154
155 if data.len() != 1 {
156 return IoResult::Err(IoError::InvalidAccessSize);
157 }
158
159 if self.tx_buffer.len() >= TX_BUFFER_MAX {
160 tracing::debug!("debugcon buffer overrun, dropping output data");
161 return IoResult::Ok;
162 }
163
164 self.tx_buffer.push_back(data[0]);
165
166 if data[0] == b'\n' {
171 self.tx_buffer.push_back(b'\r')
172 }
173
174 self.sync();
175
176 IoResult::Ok
177 }
178
179 fn get_static_regions(&mut self) -> &[(&str, RangeInclusive<u16>)] {
180 std::slice::from_ref(&self.io_region)
181 }
182}
183
184mod save_restore {
185 use crate::SerialDebugcon;
186 use vmcore::save_restore::NoSavedState;
187 use vmcore::save_restore::RestoreError;
188 use vmcore::save_restore::SaveError;
189 use vmcore::save_restore::SaveRestore;
190
191 impl SaveRestore for SerialDebugcon {
192 type SavedState = NoSavedState;
193
194 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
195 Ok(NoSavedState)
196 }
197
198 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
199 let NoSavedState = state;
200 Ok(())
201 }
202 }
203}