Alioth Code Coverage

serial.rs0.00%

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) {
97 self.0 = (self.0 & !0b1111) | 0b0100;
98 }
99
100 pub fn set_tx_room_empty(&mut self) {
101 self.0 = (self.0 & !0b1111) | 0b0010;
102 }
103
104 pub fn clear_interrupt(&mut self) {
105 self.0 = (self.0 & !0b1111) | 1;
106 }
107}
108
109impl Default for InterruptIdentification {
110 fn default() -> Self {
111 let mut val = InterruptIdentification(0);
112 val.clear_interrupt();
113 val
114 }
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 {
133 LineControl(0b00000011) // 8 data bits as default
134 }
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 {
165 LineStatus::TX_EMPTY | LineStatus::TX_HOLDING_REGISTER_EMPTY
166 }
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 {
201 8
202 }
203
204 fn read(&self, offset: u64, _size: u8) -> Result<u64, mem::Error> {
205 let mut reg = self.reg.lock();
206 let ret = match offset as u16 {
207 DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => reg.divisor as u8,
208 DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {
209 (reg.divisor >> 8) as u8
210 }
211 RX_BUFFER_REGISTER => {
212 if reg.data.len() <= 1 {
213 reg.line_status &= !LineStatus::DATA_READY;
214 }
215 reg.data.pop_front().unwrap_or(0xff)
216 }
217 INTERRUPT_ENABLE_REGISTER => reg.interrupt_enable.bits(),
218 INTERRUPT_IDENTIFICATION_REGISTER => {
219 let ret = reg.interrupt_identification.0;
220 reg.interrupt_identification.clear_interrupt();
221 ret
222 }
223 LINE_CONTROL_REGISTER => reg.line_control.0,
224 MODEM_CONTROL_REGISTER => reg.modem_control.0,
225 LINE_STATUS_REGISTER => reg.line_status.bits(),
226 MODEM_STATUS_REGISTER => reg.modem_status,
227 SCRATCH_REGISTER => reg.scratch,
228 _ => {
229 log::error!("{}: read unreachable offset {offset:#x}", self.name,);
230 0x0
231 }
232 };
233 Ok(ret as u64)
234 }
235
236 fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {
237 let byte = val as u8;
238 let mut reg = self.reg.lock();
239 match offset as u16 {
240 DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => {
241 reg.divisor = (reg.divisor & 0xff00) | byte as u16;
242 }
243 DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {
244 reg.divisor = (reg.divisor & 0x00ff) | ((byte as u16) << 8);
245 }
246 TX_HOLDING_REGISTER => {
247 if reg.modem_control.loop_back() {
248 reg.data.push_back(byte);
249 if reg
250 .interrupt_enable
251 .contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)
252 {
253 reg.interrupt_identification.set_rx_data_available();
254 self.send_irq();
255 }
256 reg.line_status |= LineStatus::DATA_READY;
257 } else {
258 let _ = self.console.as_ref().write(&[byte]);
259 if reg
260 .interrupt_enable
261 .contains(InterruptEnable::TX_HOLDING_REGISTER_EMPTY)
262 {
263 reg.interrupt_identification.set_tx_room_empty();
264 self.send_irq()
265 }
266 }
267 }
268 INTERRUPT_ENABLE_REGISTER => {
269 reg.interrupt_enable = InterruptEnable::from_bits_truncate(byte);
270 }
271 FIFO_CONTROL_REGISTER => {}
272 LINE_CONTROL_REGISTER => {
273 reg.line_control = LineControl(byte);
274 }
275 MODEM_CONTROL_REGISTER => {
276 reg.modem_control = ModemControl(byte);
277 }
278 LINE_STATUS_REGISTER => {}
279 MODEM_STATUS_REGISTER => {}
280 SCRATCH_REGISTER => {
281 reg.scratch = byte;
282 }
283 _ => log::error!("{}: write unreachable offset {:#x}", self.name, offset),
284 }
285 Ok(Action::None)
286 }
287}
288
289impl<M, C> Pause for Serial<M, C>
290where
291 M: MsiSender,
292{
293 fn pause(&self) -> device::Result<()> {
294 Ok(())
295 }
296
297 fn resume(&self) -> device::Result<()> {
298 Ok(())
299 }
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]) {
319 let mut reg = self.reg.lock();
320 reg.data.extend(bytes);
321 if reg
322 .interrupt_enable
323 .contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)
324 {
325 reg.interrupt_identification.set_rx_data_available();
326 if let Err(e) = self.io_apci.service_pin(self.pin) {
327 log::error!("{}: sending interrupt: {e:?}", self.name);
328 }
329 }
330 reg.line_status |= LineStatus::DATA_READY;
331 }
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> {
341 let reg = Arc::new(Mutex::new(SerialReg::default()));
342 let console = Arc::new(console);
343 let name: Arc<str> = Arc::from(format!("serial_{base_port:#x}"));
344 let uart_recv = SerialRecv {
345 io_apci: io_apci.clone(),
346 pin,
347 name: name.clone(),
348 reg: reg.clone(),
349 };
350 let thread = ConsoleThread::new(name.clone(), uart_recv, console.clone())?;
351 let serial = Serial {
352 name,
353 reg,
354 pin,
355 io_apci,
356 console,
357 _thread: thread,
358 };
359 Ok(serial)
360 }
361
362 fn send_irq(&self) {
363 if let Err(e) = self.io_apci.service_pin(self.pin) {
364 log::error!("{}: sending interrupt: {e:?}", self.name);
365 }
366 }
367}
368