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;
17use std::sync::Arc;
18
19use bitfield::bitfield;
20use parking_lot::Mutex;
21
22use crate::device::console::{Console, UartRecv};
23use crate::device::ioapic::IoApic;
24use crate::device::{self, MmioDev, Pause};
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> {
186 name: Arc<str>,
187 io_apci: Arc<IoApic<M>>,
188 pin: u8,
189 reg: Arc<Mutex<SerialReg>>,
190 console: Console,
191}
192
193impl<M> Mmio for Serial<M>
194where
195 M: MsiSender,
196{
197 fn size(&self) -> u64 {
198 8
199 }
200
201 fn read(&self, offset: u64, _size: u8) -> Result<u64, mem::Error> {
202 let mut reg = self.reg.lock();
203 let ret = match offset as u16 {
204 DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => reg.divisor as u8,
205 DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {
206 (reg.divisor >> 8) as u8
207 }
208 RX_BUFFER_REGISTER => {
209 if reg.data.len() <= 1 {
210 reg.line_status &= !LineStatus::DATA_READY;
211 }
212 reg.data.pop_front().unwrap_or(0xff)
213 }
214 INTERRUPT_ENABLE_REGISTER => reg.interrupt_enable.bits(),
215 INTERRUPT_IDENTIFICATION_REGISTER => {
216 let ret = reg.interrupt_identification.0;
217 reg.interrupt_identification.clear_interrupt();
218 ret
219 }
220 LINE_CONTROL_REGISTER => reg.line_control.0,
221 MODEM_CONTROL_REGISTER => reg.modem_control.0,
222 LINE_STATUS_REGISTER => reg.line_status.bits(),
223 MODEM_STATUS_REGISTER => reg.modem_status,
224 SCRATCH_REGISTER => reg.scratch,
225 _ => {
226 log::error!("{}: read unreachable offset {offset:#x}", self.name,);
227 0x0
228 }
229 };
230 Ok(ret as u64)
231 }
232
233 fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {
234 let byte = val as u8;
235 let mut reg = self.reg.lock();
236 match offset as u16 {
237 DIVISOR_LATCH_LSB if reg.line_control.divisor_latch_access() => {
238 reg.divisor = (reg.divisor & 0xff00) | byte as u16;
239 }
240 DIVISOR_LATCH_MSB if reg.line_control.divisor_latch_access() => {
241 reg.divisor = (reg.divisor & 0x00ff) | ((byte as u16) << 8);
242 }
243 TX_HOLDING_REGISTER => {
244 if reg.modem_control.loop_back() {
245 reg.data.push_back(byte);
246 if reg
247 .interrupt_enable
248 .contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)
249 {
250 reg.interrupt_identification.set_rx_data_available();
251 self.send_irq();
252 }
253 reg.line_status |= LineStatus::DATA_READY;
254 } else {
255 self.console.transmit(&[byte]);
256 if reg
257 .interrupt_enable
258 .contains(InterruptEnable::TX_HOLDING_REGISTER_EMPTY)
259 {
260 reg.interrupt_identification.set_tx_room_empty();
261 self.send_irq()
262 }
263 }
264 }
265 INTERRUPT_ENABLE_REGISTER => {
266 reg.interrupt_enable = InterruptEnable::from_bits_truncate(byte);
267 }
268 FIFO_CONTROL_REGISTER => {}
269 LINE_CONTROL_REGISTER => {
270 reg.line_control = LineControl(byte);
271 }
272 MODEM_CONTROL_REGISTER => {
273 reg.modem_control = ModemControl(byte);
274 }
275 LINE_STATUS_REGISTER => {}
276 MODEM_STATUS_REGISTER => {}
277 SCRATCH_REGISTER => {
278 reg.scratch = byte;
279 }
280 _ => log::error!("{}: write unreachable offset {:#x}", self.name, offset),
281 }
282 Ok(Action::None)
283 }
284}
285
286impl<M> Pause for Serial<M>
287where
288 M: MsiSender,
289{
290 fn pause(&self) -> device::Result<()> {
291 Ok(())
292 }
293
294 fn resume(&self) -> device::Result<()> {
295 Ok(())
296 }
297}
298
299impl<M> MmioDev for Serial<M> where M: MsiSender {}
300
301struct SerialRecv<M: MsiSender> {
302 pub name: Arc<str>,
303 pub io_apci: Arc<IoApic<M>>,
304 pub pin: u8,
305 pub reg: Arc<Mutex<SerialReg>>,
306}
307
308impl<M: MsiSender> UartRecv for SerialRecv<M> {
309 fn receive(&self, bytes: &[u8]) {
310 let mut reg = self.reg.lock();
311 reg.data.extend(bytes);
312 if reg
313 .interrupt_enable
314 .contains(InterruptEnable::RECEIVED_DATA_AVAILABLE)
315 {
316 reg.interrupt_identification.set_rx_data_available();
317 if let Err(e) = self.io_apci.service_pin(self.pin) {
318 log::error!("{}: sending interrupt: {e:?}", self.name);
319 }
320 }
321 reg.line_status |= LineStatus::DATA_READY;
322 }
323}
324
325impl<M> Serial<M>
326where
327 M: MsiSender,
328{
329 pub fn new(base_port: u16, io_apci: Arc<IoApic<M>>, pin: u8) -> io::Result<Self> {
330 let reg = Arc::new(Mutex::new(SerialReg::default()));
331 let name: Arc<str> = Arc::from(format!("serial_{base_port:#x}"));
332 let uart_recv = SerialRecv {
333 io_apci: io_apci.clone(),
334 pin,
335 name: name.clone(),
336 reg: reg.clone(),
337 };
338 let console = Console::new(name.clone(), uart_recv)?;
339 let serial = Serial {
340 name,
341 reg,
342 pin,
343 io_apci,
344 console,
345 };
346 Ok(serial)
347 }
348
349 fn send_irq(&self) {
350 if let Err(e) = self.io_apci.service_pin(self.pin) {
351 log::error!("{}: sending interrupt: {e:?}", self.name);
352 }
353 }
354}
355