Alioth Code Coverage

serial.rs87.33%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::VecDeque;
16use std::io::{Read, Write};
17use std::sync::Arc;
18
19use bitfield::bitfield;
20use parking_lot::Mutex;
21
22use crate::device::console::{Console, ConsoleThread, UartRecv};
23use crate::device::ioapic::IoApic;
24use crate::device::{self, MmioDev, Pause, Result};
25use crate::hv::MsiSender;
26use crate::mem::emulated::{Action, Mmio};
27use crate::{bitflags, mem};
28
29const TX_HOLDING_REGISTER: u16 = 0x0;
30const RX_BUFFER_REGISTER: u16 = 0x0;
31const DIVISOR_LATCH_LSB: u16 = 0x0;
32const DIVISOR_LATCH_MSB: u16 = 0x1;
33const INTERRUPT_ENABLE_REGISTER: u16 = 0x1;
34const FIFO_CONTROL_REGISTER: u16 = 0x2;
35const INTERRUPT_IDENTIFICATION_REGISTER: u16 = 0x2;
36const LINE_CONTROL_REGISTER: u16 = 0x3;
37const MODEM_CONTROL_REGISTER: u16 = 0x4;
38const LINE_STATUS_REGISTER: u16 = 0x5;
39const MODEM_STATUS_REGISTER: u16 = 0x6;
40const SCRATCH_REGISTER: u16 = 0x7;
41
42// offset 0x1, Interrupt Enable Register (IER)
43bitflags! {
44 #[derive(Default)]
45 pub struct InterruptEnable(u8) {
46 MODEM_STATUS = 1 << 3;
47 RECEIVER_LINE_STATUS = 1 << 2;
48 TX_HOLDING_REGISTER_EMPTY = 1 << 1;
49 RECEIVED_DATA_AVAILABLE = 1 << 0;
50 }
51}
52
53// offset 0x2, write, FIFO Control Register (FCR)
54bitfield! {
55 #[derive(Copy, Clone, Default)]
56 pub struct FifoControl(u8);
57 impl Debug;
58 rx_trigger_size_bits, _: 7, 6;
59 dma_mode, _: 3;
60 tx_reset, _: 2;
61 rx_reset, _: 1;
62 fifo_enabled, _: 0;
63}
64
65impl FifoControl {
66 pub fn rx_trigger_size(&self) -> usize {
67 match self.rx_trigger_size_bits() {
68 0b00 => 1,
69 0b01 => 4,
70 0b10 => 8,
71 0b11 => 14,
72 _ => unreachable!(),
73 }
74 }
75}
76
77// offset 0x2, read, Interrupt Identification Register
78bitfield! {
79 #[derive(Copy, Clone)]
80 pub struct InterruptIdentification(u8);
81 impl Debug;
82 fifo_enabled, _: 7, 6;
83 interrupt_id, set_interrupt_id: 3,1;
84 no_pending, set_no_pending: 0; // Interrupt Pending Bit
85}
86
87impl InterruptIdentification {
88 pub fn set_fifo_enabled(&mut self) {
89 self.0 |= 0b11 << 6;
90 }
91
92 pub fn clear_fifi_enabled(&mut self) {
93 self.0 &= !(0b11 << 6);
94 }
95
96 pub fn set_rx_data_available(&mut self) {6x
97 self.0 = (self.0 & !0b1111) | 0b0100;6x
98 }6x
99
100 pub fn set_tx_room_empty(&mut self) {3x
101 self.0 = (self.0 & !0b1111) | 0b0010;3x
102 }3x
103
104 pub fn clear_interrupt(&mut self) {27x
105 self.0 = (self.0 & !0b1111) | 1;27x
106 }27x
107}
108
109impl Default for InterruptIdentification {
110 fn default() -> Self {18x
111 let mut val = InterruptIdentification(0);18x
112 val.clear_interrupt();18x
113 val18x
114 }18x
115}
116
117// offset 0x3, Line Control Register (LCR)
118bitfield! {
119 #[derive(Copy, Clone)]
120 pub struct LineControl(u8);
121 impl Debug;
122 divisor_latch_access, _: 7;
123 break_, _: 6;
124 stick_parity, _: 5;
125 even_parity, _: 4;
126 parity_enabled, _: 3;
127 step_bits, _: 2;
128 word_length, _: 1, 0;
129}
130
131impl Default for LineControl {
132 fn default() -> Self {18x
133 LineControl(0b00000011) // 8 data bits as default18x
134 }18x
135}
136
137// offset 0x4, Modem Control Register
138bitfield! {
139 #[derive(Copy, Clone, Default)]
140 pub struct ModemControl(u8);
141 impl Debug;
142 loop_back, _: 4;
143 out_2, _: 3;
144 out_1, _: 2;
145 request_to_send, _: 1;
146 data_terminal_ready, _: 0; // Data Terminal Ready
147}
148
149// offset 0x5, Line Status Register (LSR)
150bitflags! {
151 pub struct LineStatus(u8) {
152 ERROR_IN_RX_FIFO = 1 << 7;
153 TX_EMPTY = 1 << 6;
154 TX_HOLDING_REGISTER_EMPTY = 1 << 5;
155 BREAK_INTERRUPT = 1 << 4;
156 FRAMING_ERROR = 1 << 3;
157 PARITY_ERROR = 1 << 2;
158 OVERRUN_ERROR = 1 << 1;
159 DATA_READY = 1 << 0;
160 }
161}
162
163impl Default for LineStatus {
164 fn default() -> Self {18x
165 LineStatus::TX_EMPTY | LineStatus::TX_HOLDING_REGISTER_EMPTY18x
166 }18x
167}
168
169#[derive(Default, Debug)]
170struct SerialReg {
171 interrupt_enable: InterruptEnable, // 0x1, Interrupt Enable Register (IER)
172 #[allow(dead_code)]
173 fifo_control: FifoControl, // 0x2, write, FIFO Control Register (FCR)
174 interrupt_identification: InterruptIdentification, // 0x2, read, Interrupt Identification Register
175 line_control: LineControl, // 0x3, Line Control Register (LCR)
176 modem_control: ModemControl, // 0x4, Modem Control Register (MCR)
177 line_status: LineStatus,
178 modem_status: u8, // 0x6, Modem Status Register (MSR)
179 scratch: u8, // 0x7, Scratch Register (SCR)
180 divisor: u16,
181 data: VecDeque<u8>,
182}
183
184#[derive(Debug)]
185pub struct Serial<M: MsiSender, C> {
186 name: Arc<str>,
187 io_apci: Arc<IoApic<M>>,
188 pin: u8,
189 reg: Arc<Mutex<SerialReg>>,
190 console: Arc<C>,
191 _thread: ConsoleThread,
192}
193
194impl<M, C> Mmio for Serial<M, C>
195where
196 M: MsiSender,
197 C: Console,
198 for<'a> &'a C: Read + Write,
199{
200 fn size(&self) -> u64 {3x
201 83x
202 }3x
203
204 fn read(&self, offset: u64, _size: u8) -> Result<u64, mem::Error> {63x
205 let mut reg = self.reg.lock();63x
206 let ret = match offset as u16 {63x
207 DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => reg.divisor as u8,12x
208 DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {3x
209 (reg.divisor >> 8) as u83x
210 }
211 RX_BUFFER_REGISTER => {
212 if reg.data.len() <= 1 {9x
213 reg.line_status &= !LineStatus::DATA_READY;9x
214 }9x
215 reg.data.pop_front().unwrap_or(0xff)9x
216 }
217 INTERRUPT_ENABLE_REGISTER => reg.interrupt_enable.bits(),
218 INTERRUPT_IDENTIFICATION_REGISTER => {
219 let ret = reg.interrupt_identification.0;9x
220 reg.interrupt_identification.clear_interrupt();9x
221 ret9x
222 }
223 LINE_CONTROL_REGISTER => reg.line_control.0,6x
224 MODEM_CONTROL_REGISTER => reg.modem_control.0,3x
225 LINE_STATUS_REGISTER => reg.line_status.bits(),21x
226 MODEM_STATUS_REGISTER => reg.modem_status,3x
227 SCRATCH_REGISTER => reg.scratch,3x
228 _ => {
229 log::error!("{}: read unreachable offset {offset:#x}", self.name,);3x
230 0x03x
231 }
232 };
233 Ok(ret as u64)63x
234 }63x
235
236 fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {48x
237 let byte = val as u8;48x
238 let mut reg = self.reg.lock();48x
239 match offset as u16 {48x
240 DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => {9x
241 reg.divisor = (reg.divisor & 0xff00) | byte as u16;3x
242 }3x
243 DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {15x
244 reg.divisor = (reg.divisor & 0x00ff) | ((byte as u16) << 8);3x
245 }3x
246 TX_HOLDING_REGISTER => {
247 if reg.modem_control.loop_back() {6x
248 reg.data.push_back(byte);3x
249 if reg3x
250 .interrupt_enable3x
251 .contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)3x
252 {3x
253 reg.interrupt_identification.set_rx_data_available();3x
254 self.send_irq();3x
255 }3x
256 reg.line_status |= LineStatus::DATA_READY;3x
257 } else {
258 let _ = self.console.as_ref().write(&[byte]);3x
259 if reg3x
260 .interrupt_enable3x
261 .contains(InterruptEnable::TX_HOLDING_REGISTER_EMPTY)3x
262 {
263 reg.interrupt_identification.set_tx_room_empty();3x
264 self.send_irq()3x
265 }
266 }
267 }
268 INTERRUPT_ENABLE_REGISTER => {12x
269 reg.interrupt_enable = InterruptEnable::from_bits_truncate(byte);12x
270 }12x
271 FIFO_CONTROL_REGISTER => {}3x
272 LINE_CONTROL_REGISTER => {6x
273 reg.line_control = LineControl(byte);6x
274 }6x
275 MODEM_CONTROL_REGISTER => {6x
276 reg.modem_control = ModemControl(byte);6x
277 }6x
278 LINE_STATUS_REGISTER => {}
279 MODEM_STATUS_REGISTER => {}3x
280 SCRATCH_REGISTER => {3x
281 reg.scratch = byte;3x
282 }3x
283 _ => log::error!("{}: write unreachable offset {:#x}", self.name, offset),3x
284 }
285 Ok(Action::None)48x
286 }48x
287}
288
289impl<M, C> Pause for Serial<M, C>
290where
291 M: MsiSender,
292{
293 fn pause(&self) -> device::Result<()> {3x
294 Ok(())3x
295 }3x
296
297 fn resume(&self) -> device::Result<()> {3x
298 Ok(())3x
299 }3x
300}
301
302impl<M, C> MmioDev for Serial<M, C>
303where
304 M: MsiSender,
305 C: Console,
306 for<'a> &'a C: Read + Write,
307{
308}
309
310struct SerialRecv<M: MsiSender> {
311 pub name: Arc<str>,
312 pub io_apci: Arc<IoApic<M>>,
313 pub pin: u8,
314 pub reg: Arc<Mutex<SerialReg>>,
315}
316
317impl<M: MsiSender> UartRecv for SerialRecv<M> {
318 fn receive(&self, bytes: &[u8]) {6x
319 let mut reg = self.reg.lock();6x
320 reg.data.extend(bytes);6x
321 if reg6x
322 .interrupt_enable6x
323 .contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)6x
324 {
325 reg.interrupt_identification.set_rx_data_available();3x
326 if let Err(e) = self.io_apci.service_pin(self.pin) {3x
327 log::error!("{}: sending interrupt: {e:?}", self.name);
328 }3x
329 }3x
330 reg.line_status |= LineStatus::DATA_READY;6x
331 }6x
332}
333
334impl<M, C> Serial<M, C>
335where
336 M: MsiSender,
337 C: Console,
338 for<'a> &'a C: Read + Write,
339{
340 pub fn new(base_port: u16, io_apci: Arc<IoApic<M>>, pin: u8, console: C) -> Result<Self> {18x
341 let reg = Arc::new(Mutex::new(SerialReg::default()));18x
342 let console = Arc::new(console);18x
343 let name: Arc<str> = Arc::from(format!("serial_{base_port:#x}"));18x
344 let uart_recv = SerialRecv {18x
345 io_apci: io_apci.clone(),18x
346 pin,18x
347 name: name.clone(),18x
348 reg: reg.clone(),18x
349 };18x
350 let thread = ConsoleThread::new(name.clone(), uart_recv, console.clone())?;18x
351 let serial = Serial {18x
352 name,18x
353 reg,18x
354 pin,18x
355 io_apci,18x
356 console,18x
357 _thread: thread,18x
358 };18x
359 Ok(serial)18x
360 }18x
361
362 fn send_irq(&self) {6x
363 if let Err(e) = self.io_apci.service_pin(self.pin) {6x
364 log::error!("{}: sending interrupt: {e:?}", self.name);
365 }6x
366 }6x
367}
368
369#[cfg(test)]
370#[path = "serial_test.rs"]
371mod tests;
372