Alioth Code Coverage

pl011.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 parking_lot::Mutex;
20
21use crate::device::console::{Console, UartRecv};
22use crate::device::{self, MmioDev, Pause};
23use crate::hv::IrqSender;
24use crate::mem::emulated::{Action, Mmio};
25use crate::{bitflags, hv, mem};
26
27/// RW width 12/8 Data Register
28const UART_DR: u64 = 0x0;
29/// RO width 4 Receive Status Register
30const UART_RSR: u64 = 0x4;
31/// WO width 0  Error Clear Register
32const UART_ECR: u64 = 0x4;
33/// RO width 9 Flag Register
34const UART_FR: u64 = 0x18;
35/// RW width 8 IrDA Low-Power Counter Register
36const UART_ILPR: u64 = 0x20;
37/// RW width 16 Integer Baud Rate Register
38const UART_IBRD: u64 = 0x24;
39/// RW width 6 Fractional Baud Rate Register
40const UART_FBRD: u64 = 0x28;
41/// RW width 8 Line Control Register
42const UART_LCR_H: u64 = 0x2C;
43/// RW width 16 Control Register
44const UART_CR: u64 = 0x30;
45/// RW width 6 Interrupt FIFO Level Select Register
46const UART_IFLS: u64 = 0x34;
47/// RW width 11 Interrupt Mask Set/Clear Register
48const UART_IMSC: u64 = 0x38;
49/// RO width 11 Raw Interrupt Status Register
50const UART_RIS: u64 = 0x3C;
51/// RO width 11 Masked Interrupt Status Register
52const UART_MIS: u64 = 0x40;
53/// WO width 11 Interrupt Clear Register
54const UART_ICR: u64 = 0x44;
55/// RW width 3 DMA Control Register
56const UART_DMACR: u64 = 0x48;
57/// RO width 8 UARTPeriphID0 Register
58const UART_PERIPH_ID0: u64 = 0xFE0;
59/// RO width 8 UARTPeriphID1 Register
60const UART_PERIPH_ID1: u64 = 0xFE4;
61/// RO width 8 UARTPeriphID2 Register
62const UART_PERIPH_ID2: u64 = 0xFE8;
63/// RO width 8 UARTPeriphID3 Register
64const UART_PERIPH_ID3: u64 = 0xFEC;
65/// RO width 8 UARTPCellID0 Register
66const UART_PCELL_ID0: u64 = 0xFF0;
67/// RO width 8 UARTPCellID1 Register
68const UART_PCELL_ID1: u64 = 0xFF4;
69/// RO width 8 UARTPCellID2 Register
70const UART_PCELL_ID2: u64 = 0xFF8;
71/// RO width 8 UARTPCellID3 Register
72const UART_PCELL_ID3: u64 = 0xFFC;
73
74// https://developer.arm.com/documentation/ddi0183/g/programmers-model/register-descriptions/peripheral-identification-registers--uartperiphid0-3
75const PERIPH_ID: [u32; 4] = [0x11, 0x10, 0x14, 0x00];
76
77// https://developer.arm.com/documentation/ddi0183/g/programmers-model/register-descriptions/primecell-identification-registers--uartpcellid0-3
78const PCELL_ID: [u32; 4] = [0x0d, 0xf0, 0x05, 0xb1];
79
80bitflags! {
81 #[derive(Default)]
82 pub struct Flag(u16) {
83 RI = 1 << 8;
84 /// Transmit FIFO empty
85 TXFE = 1 << 7;
86 /// Receive FIFO full
87 RXFF = 1 << 6;
88 /// Transmit FIFO full.
89 TXFF = 1 << 5;
90 /// Receive FIFO empty
91 RXFE = 1 << 4;
92 BUSY = 1 << 3;
93 DCD = 1 << 2;
94 DSR = 1 << 1;
95 CTS = 1 << 0;
96 }
97}
98
99bitflags! {
100 #[derive(Default)]
101 pub struct Interrupt(u16) {
102 /// Overrun error interrupt status.
103 OERIS = 1 << 10;
104 /// Break error interrupt status.
105 BERIS = 1 << 9;
106 /// Parity error interrupt status.
107 PERIS = 1 << 8;
108 /// Framing error interrupt status.
109 FERIS = 1 << 7;
110 /// Receive timeout interrupt status.
111 RTRIS = 1 << 6;
112 /// Transmit interrupt status.
113 TXRIS = 1 << 5;
114 /// Receive interrupt status.
115 RXRIS = 1 << 4;
116 /// nUARTDSR modem interrupt status.
117 DSRRMIS = 1 << 3;
118 /// nUARTDCD modem interrupt status.
119 DCDRMIS = 1 << 2;
120 /// nUARTCTS modem interrupt status.
121 CTSRMIS = 1 << 1;
122 /// nUARTRI modem interrupt status.
123 RIRMIS = 1 << 0;
124 }
125}
126
127#[derive(Debug, Default)]
128struct Pl011Reg {
129 data: VecDeque<u8>,
130 flag: Flag,
131 lcr: u32,
132 rsr: u32,
133 cr: u32,
134 dmacr: u32,
135 ilpr: u32,
136 ibrd: u32,
137 fbrd: u32,
138 ifl: u32,
139 interrupt_mask: Interrupt,
140 interrupt_status: Interrupt,
141}
142
143/// https://developer.arm.com/documentation/ddi0183/g
144#[derive(Debug)]
145pub struct Pl011<I> {
146 name: Arc<str>,
147 irq_line: Arc<I>,
148 reg: Arc<Mutex<Pl011Reg>>,
149 console: Console,
150}
151
152impl<I> Pl011<I>
153where
154 I: IrqSender,
155{
156 pub fn new(base_addr: u64, irq_line: I) -> io::Result<Self> {
157 let irq_line = Arc::new(irq_line);
158 let reg = Arc::new(Mutex::new(Pl011Reg::default()));
159 let name: Arc<str> = Arc::from(format!("pl011@{base_addr:#x}"));
160 let pl011_recv = Pl011Recv {
161 irq_line: irq_line.clone(),
162 reg: reg.clone(),
163 };
164 let console = Console::new(name.clone(), pl011_recv)?;
165 let pl011 = Pl011 {
166 name,
167 irq_line,
168 reg,
169 console,
170 };
171 Ok(pl011)
172 }
173
174 fn update_interrupt(&self, reg: &Pl011Reg) -> Result<(), hv::Error> {
175 if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {
176 self.irq_line.send().unwrap();
177 }
178 Ok(())
179 }
180}
181
182impl<I> Mmio for Pl011<I>
183where
184 I: IrqSender,
185{
186 fn size(&self) -> u64 {
187 0x1000
188 }
189
190 fn read(&self, offset: u64, _size: u8) -> mem::Result<u64> {
191 let mut reg = self.reg.lock();
192 let ret = match offset {
193 UART_DR => {
194 let byte = reg.data.pop_front().unwrap_or(0);
195 if reg.data.is_empty() {
196 reg.flag.insert(Flag::RXFE);
197 reg.interrupt_status.remove(Interrupt::RXRIS);
198 }
199 self.update_interrupt(&reg)?;
200 byte as u32
201 }
202 UART_RSR => reg.rsr,
203 UART_FR => reg.flag.bits() as u32,
204 UART_ILPR => reg.ilpr,
205 UART_IBRD => reg.ibrd,
206 UART_FBRD => reg.fbrd,
207 UART_LCR_H => reg.lcr,
208 UART_CR => reg.cr,
209 UART_IFLS => reg.ifl,
210 UART_IMSC => reg.interrupt_mask.bits() as u32,
211 UART_RIS => reg.interrupt_status.bits() as u32,
212 UART_MIS => (reg.interrupt_mask & reg.interrupt_status).bits() as u32,
213 UART_ICR => {
214 log::error!("{}: UART_ICR is write only", self.name);
215 0
216 }
217 UART_DMACR => reg.dmacr,
218 UART_PERIPH_ID0 => PERIPH_ID[0],
219 UART_PERIPH_ID1 => PERIPH_ID[1],
220 UART_PERIPH_ID2 => PERIPH_ID[2],
221 UART_PERIPH_ID3 => PERIPH_ID[3],
222 UART_PCELL_ID0 => PCELL_ID[0],
223 UART_PCELL_ID1 => PCELL_ID[1],
224 UART_PCELL_ID2 => PCELL_ID[2],
225 UART_PCELL_ID3 => PCELL_ID[3],
226 _ => 0,
227 };
228 Ok(ret as u64)
229 }
230
231 fn write(&self, offset: u64, _size: u8, val: u64) -> mem::Result<Action> {
232 let mut reg = self.reg.lock();
233 match offset {
234 UART_DR => {
235 self.console.transmit(&[val as u8]);
236 reg.interrupt_status.insert(Interrupt::TXRIS);
237 reg.flag.insert(Flag::TXFE);
238 self.update_interrupt(&reg)?;
239 }
240 UART_ECR => reg.rsr = 0,
241 UART_FR => log::error!("{}: UART_FR is read only", self.name),
242 UART_ILPR => reg.ilpr = val as u32,
243 UART_IBRD => reg.ibrd = val as u32,
244 UART_FBRD => reg.fbrd = val as u32,
245 UART_LCR_H => reg.lcr = val as u32,
246 UART_CR => reg.cr = val as u32,
247 UART_IFLS => reg.ifl = val as u32,
248 UART_IMSC => {
249 reg.interrupt_mask = Interrupt::from_bits_truncate(val as u16);
250 }
251 UART_RIS => log::error!("{}, UART_RIS is read only", self.name),
252 UART_MIS => log::error!("{}, UART_MIS is read only", self.name),
253 UART_ICR => reg.interrupt_status &= !Interrupt::from_bits_truncate(val as u16),
254 UART_DMACR => reg.dmacr = val as u32,
255 _ => {}
256 }
257 Ok(Action::None)
258 }
259}
260
261impl<I> Pause for Pl011<I>
262where
263 I: IrqSender,
264{
265 fn pause(&self) -> device::Result<()> {
266 Ok(())
267 }
268
269 fn resume(&self) -> device::Result<()> {
270 Ok(())
271 }
272}
273
274impl<I> MmioDev for Pl011<I> where I: IrqSender {}
275
276struct Pl011Recv<I: IrqSender> {
277 irq_line: Arc<I>,
278 reg: Arc<Mutex<Pl011Reg>>,
279}
280
281impl<I: IrqSender> UartRecv for Pl011Recv<I> {
282 fn receive(&self, bytes: &[u8]) {
283 let mut reg = self.reg.lock();
284 reg.data.extend(bytes);
285 reg.interrupt_status.insert(Interrupt::RXRIS);
286 reg.flag.remove(Flag::RXFE);
287
288 if (reg.interrupt_status & reg.interrupt_mask).bits() != 0 {
289 self.irq_line.send().unwrap();
290 }
291 }
292}
293