xref: /cloud-hypervisor/devices/src/legacy/uart_pl011.rs (revision 1b91aa8ef3ba490a12853d41783ed558cf7b7060)
1fd95acc6SHenry Wang // Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
2fd95acc6SHenry Wang // SPDX-License-Identifier: Apache-2.0
3fd95acc6SHenry Wang 
4fd95acc6SHenry Wang //! ARM PrimeCell UART(PL011)
5fd95acc6SHenry Wang //!
6fd95acc6SHenry Wang //! This module implements an ARM PrimeCell UART(PL011).
7fd95acc6SHenry Wang //!
8fd95acc6SHenry Wang 
9fd95acc6SHenry Wang use std::collections::VecDeque;
10fd95acc6SHenry Wang use std::sync::{Arc, Barrier};
11707cea21SRob Bradford use std::time::Instant;
12fd95acc6SHenry Wang use std::{io, result};
1388a9f799SRob Bradford 
1488a9f799SRob Bradford use serde::{Deserialize, Serialize};
1589b429c7SSamrutGadde use thiserror::Error;
16fd95acc6SHenry Wang use vm_device::interrupt::InterruptSourceGroup;
17fd95acc6SHenry Wang use vm_device::BusDevice;
1810ab87d6SRob Bradford use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
19fd95acc6SHenry Wang 
2088a9f799SRob Bradford use crate::{read_le_u32, write_le_u32};
2188a9f799SRob Bradford 
22fd95acc6SHenry Wang /* Registers */
23fd95acc6SHenry Wang const UARTDR: u64 = 0;
24fd95acc6SHenry Wang const UARTRSR_UARTECR: u64 = 1;
25fd95acc6SHenry Wang const UARTFR: u64 = 6;
26fd95acc6SHenry Wang const UARTILPR: u64 = 8;
27fd95acc6SHenry Wang const UARTIBRD: u64 = 9;
28fd95acc6SHenry Wang const UARTFBRD: u64 = 10;
29fd95acc6SHenry Wang const UARTLCR_H: u64 = 11;
30fd95acc6SHenry Wang const UARTCR: u64 = 12;
31fd95acc6SHenry Wang const UARTIFLS: u64 = 13;
32fd95acc6SHenry Wang const UARTIMSC: u64 = 14;
33fd95acc6SHenry Wang const UARTRIS: u64 = 15;
34fd95acc6SHenry Wang const UARTMIS: u64 = 16;
35fd95acc6SHenry Wang const UARTICR: u64 = 17;
36fd95acc6SHenry Wang const UARTDMACR: u64 = 18;
376dbc1362SJianyong Wu const UARTDEBUG: u64 = 0x3c0;
38fd95acc6SHenry Wang 
39fd95acc6SHenry Wang const PL011_INT_TX: u32 = 0x20;
40fd95acc6SHenry Wang const PL011_INT_RX: u32 = 0x10;
41fd95acc6SHenry Wang 
42fd95acc6SHenry Wang const PL011_FLAG_RXFF: u32 = 0x40;
43fd95acc6SHenry Wang const PL011_FLAG_RXFE: u32 = 0x10;
44fd95acc6SHenry Wang 
45fd95acc6SHenry Wang const PL011_ID: [u8; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
46fd95acc6SHenry Wang // We are only interested in the margins.
47fd95acc6SHenry Wang const AMBA_ID_LOW: u64 = 0x3f8;
48fd95acc6SHenry Wang const AMBA_ID_HIGH: u64 = 0x401;
49fd95acc6SHenry Wang 
5089b429c7SSamrutGadde #[derive(Debug, Error)]
51fd95acc6SHenry Wang pub enum Error {
5289b429c7SSamrutGadde     #[error("pl011_write: Bad Write Offset: {0}")]
53fd95acc6SHenry Wang     BadWriteOffset(u64),
54ab575a54SPhilipp Schuster     #[error("pl011: DMA not implemented")]
5540da6210SRob Bradford     DmaNotImplemented,
56*1b91aa8eSPhilipp Schuster     #[error("Failed to trigger interrupt")]
5793b599e5SPhilipp Schuster     InterruptFailure(#[source] io::Error),
58*1b91aa8eSPhilipp Schuster     #[error("Failed to write")]
5993b599e5SPhilipp Schuster     WriteAllFailure(#[source] io::Error),
60*1b91aa8eSPhilipp Schuster     #[error("Failed to flush")]
6193b599e5SPhilipp Schuster     FlushFailure(#[source] io::Error),
62fd95acc6SHenry Wang }
63fd95acc6SHenry Wang 
64fd95acc6SHenry Wang type Result<T> = result::Result<T, Error>;
65fd95acc6SHenry Wang 
66fd95acc6SHenry Wang /// A PL011 device following the PL011 specification.
6740da6210SRob Bradford pub struct Pl011 {
68fd95acc6SHenry Wang     id: String,
69fd95acc6SHenry Wang     flags: u32,
70fd95acc6SHenry Wang     lcr: u32,
71fd95acc6SHenry Wang     rsr: u32,
72fd95acc6SHenry Wang     cr: u32,
73fd95acc6SHenry Wang     dmacr: u32,
746dbc1362SJianyong Wu     debug: u32,
75fd95acc6SHenry Wang     int_enabled: u32,
76fd95acc6SHenry Wang     int_level: u32,
77fd95acc6SHenry Wang     read_fifo: VecDeque<u8>,
78fd95acc6SHenry Wang     ilpr: u32,
79fd95acc6SHenry Wang     ibrd: u32,
80fd95acc6SHenry Wang     fbrd: u32,
81fd95acc6SHenry Wang     ifl: u32,
82fd95acc6SHenry Wang     read_count: u32,
83fd95acc6SHenry Wang     read_trigger: u32,
84dcc646f5SSebastien Boeuf     irq: Arc<dyn InterruptSourceGroup>,
85fd95acc6SHenry Wang     out: Option<Box<dyn io::Write + Send>>,
866dbc1362SJianyong Wu     timestamp: std::time::Instant,
87fd95acc6SHenry Wang }
88fd95acc6SHenry Wang 
8910ab87d6SRob Bradford #[derive(Serialize, Deserialize)]
9040da6210SRob Bradford pub struct Pl011State {
91fd95acc6SHenry Wang     flags: u32,
92fd95acc6SHenry Wang     lcr: u32,
93fd95acc6SHenry Wang     rsr: u32,
94fd95acc6SHenry Wang     cr: u32,
95fd95acc6SHenry Wang     dmacr: u32,
966dbc1362SJianyong Wu     debug: u32,
97fd95acc6SHenry Wang     int_enabled: u32,
98fd95acc6SHenry Wang     int_level: u32,
99f643ba61SRob Bradford     read_fifo: Vec<u8>,
100fd95acc6SHenry Wang     ilpr: u32,
101fd95acc6SHenry Wang     ibrd: u32,
102fd95acc6SHenry Wang     fbrd: u32,
103fd95acc6SHenry Wang     ifl: u32,
104fd95acc6SHenry Wang     read_count: u32,
105fd95acc6SHenry Wang     read_trigger: u32,
106fd95acc6SHenry Wang }
107fd95acc6SHenry Wang 
10840da6210SRob Bradford impl Pl011 {
109fd95acc6SHenry Wang     /// Constructs an AMBA PL011 UART device.
new( id: String, irq: Arc<dyn InterruptSourceGroup>, out: Option<Box<dyn io::Write + Send>>, timestamp: Instant, state: Option<Pl011State>, ) -> Self110fd95acc6SHenry Wang     pub fn new(
111fd95acc6SHenry Wang         id: String,
112dcc646f5SSebastien Boeuf         irq: Arc<dyn InterruptSourceGroup>,
113fd95acc6SHenry Wang         out: Option<Box<dyn io::Write + Send>>,
114707cea21SRob Bradford         timestamp: Instant,
1159fbf52b9SSebastien Boeuf         state: Option<Pl011State>,
11640da6210SRob Bradford     ) -> Self {
1179fbf52b9SSebastien Boeuf         let (
1189fbf52b9SSebastien Boeuf             flags,
1199fbf52b9SSebastien Boeuf             lcr,
1209fbf52b9SSebastien Boeuf             rsr,
1219fbf52b9SSebastien Boeuf             cr,
1229fbf52b9SSebastien Boeuf             dmacr,
1239fbf52b9SSebastien Boeuf             debug,
1249fbf52b9SSebastien Boeuf             int_enabled,
1259fbf52b9SSebastien Boeuf             int_level,
1269fbf52b9SSebastien Boeuf             read_fifo,
1279fbf52b9SSebastien Boeuf             ilpr,
1289fbf52b9SSebastien Boeuf             ibrd,
1299fbf52b9SSebastien Boeuf             fbrd,
1309fbf52b9SSebastien Boeuf             ifl,
1319fbf52b9SSebastien Boeuf             read_count,
1329fbf52b9SSebastien Boeuf             read_trigger,
1339fbf52b9SSebastien Boeuf         ) = if let Some(state) = state {
1349fbf52b9SSebastien Boeuf             (
1359fbf52b9SSebastien Boeuf                 state.flags,
1369fbf52b9SSebastien Boeuf                 state.lcr,
1379fbf52b9SSebastien Boeuf                 state.rsr,
1389fbf52b9SSebastien Boeuf                 state.cr,
1399fbf52b9SSebastien Boeuf                 state.dmacr,
1409fbf52b9SSebastien Boeuf                 state.debug,
1419fbf52b9SSebastien Boeuf                 state.int_enabled,
1429fbf52b9SSebastien Boeuf                 state.int_level,
1439fbf52b9SSebastien Boeuf                 state.read_fifo.into(),
1449fbf52b9SSebastien Boeuf                 state.ilpr,
1459fbf52b9SSebastien Boeuf                 state.ibrd,
1469fbf52b9SSebastien Boeuf                 state.fbrd,
1479fbf52b9SSebastien Boeuf                 state.ifl,
1489fbf52b9SSebastien Boeuf                 state.read_count,
1499fbf52b9SSebastien Boeuf                 state.read_trigger,
1509fbf52b9SSebastien Boeuf             )
1519fbf52b9SSebastien Boeuf         } else {
1529fbf52b9SSebastien Boeuf             (
1539fbf52b9SSebastien Boeuf                 0x90,
1549fbf52b9SSebastien Boeuf                 0,
1559fbf52b9SSebastien Boeuf                 0,
1569fbf52b9SSebastien Boeuf                 0x300,
1579fbf52b9SSebastien Boeuf                 0,
1589fbf52b9SSebastien Boeuf                 0,
1599fbf52b9SSebastien Boeuf                 0,
1609fbf52b9SSebastien Boeuf                 0,
1619fbf52b9SSebastien Boeuf                 VecDeque::new(),
1629fbf52b9SSebastien Boeuf                 0,
1639fbf52b9SSebastien Boeuf                 0,
1649fbf52b9SSebastien Boeuf                 0,
1659fbf52b9SSebastien Boeuf                 0x12,
1669fbf52b9SSebastien Boeuf                 0,
1679fbf52b9SSebastien Boeuf                 1,
1689fbf52b9SSebastien Boeuf             )
1699fbf52b9SSebastien Boeuf         };
1709fbf52b9SSebastien Boeuf 
17140da6210SRob Bradford         Self {
172fd95acc6SHenry Wang             id,
1739fbf52b9SSebastien Boeuf             flags,
1749fbf52b9SSebastien Boeuf             lcr,
1759fbf52b9SSebastien Boeuf             rsr,
1769fbf52b9SSebastien Boeuf             cr,
1779fbf52b9SSebastien Boeuf             dmacr,
1789fbf52b9SSebastien Boeuf             debug,
1799fbf52b9SSebastien Boeuf             int_enabled,
1809fbf52b9SSebastien Boeuf             int_level,
1819fbf52b9SSebastien Boeuf             read_fifo,
1829fbf52b9SSebastien Boeuf             ilpr,
1839fbf52b9SSebastien Boeuf             ibrd,
1849fbf52b9SSebastien Boeuf             fbrd,
1859fbf52b9SSebastien Boeuf             ifl,
1869fbf52b9SSebastien Boeuf             read_count,
1879fbf52b9SSebastien Boeuf             read_trigger,
188fd95acc6SHenry Wang             irq,
189fd95acc6SHenry Wang             out,
190707cea21SRob Bradford             timestamp,
191fd95acc6SHenry Wang         }
192fd95acc6SHenry Wang     }
193fd95acc6SHenry Wang 
set_out(&mut self, out: Option<Box<dyn io::Write + Send>>)1946d1077fcSPraveen K Paladugu     pub fn set_out(&mut self, out: Option<Box<dyn io::Write + Send>>) {
1956d1077fcSPraveen K Paladugu         self.out = out;
1960066ddefSWilliam Douglas     }
1970066ddefSWilliam Douglas 
state(&self) -> Pl011State19840da6210SRob Bradford     fn state(&self) -> Pl011State {
19940da6210SRob Bradford         Pl011State {
200fd95acc6SHenry Wang             flags: self.flags,
201fd95acc6SHenry Wang             lcr: self.lcr,
202fd95acc6SHenry Wang             rsr: self.rsr,
203fd95acc6SHenry Wang             cr: self.cr,
204fd95acc6SHenry Wang             dmacr: self.dmacr,
2056dbc1362SJianyong Wu             debug: self.debug,
206fd95acc6SHenry Wang             int_enabled: self.int_enabled,
207fd95acc6SHenry Wang             int_level: self.int_level,
208f643ba61SRob Bradford             read_fifo: self.read_fifo.clone().into(),
209fd95acc6SHenry Wang             ilpr: self.ilpr,
210fd95acc6SHenry Wang             ibrd: self.ibrd,
211fd95acc6SHenry Wang             fbrd: self.fbrd,
212fd95acc6SHenry Wang             ifl: self.ifl,
213fd95acc6SHenry Wang             read_count: self.read_count,
214fd95acc6SHenry Wang             read_trigger: self.read_trigger,
215fd95acc6SHenry Wang         }
216fd95acc6SHenry Wang     }
217fd95acc6SHenry Wang 
218fd95acc6SHenry Wang     /// Queues raw bytes for the guest to read and signals the interrupt
queue_input_bytes(&mut self, c: &[u8]) -> vmm_sys_util::errno::Result<()>219fd95acc6SHenry Wang     pub fn queue_input_bytes(&mut self, c: &[u8]) -> vmm_sys_util::errno::Result<()> {
220fd95acc6SHenry Wang         self.read_fifo.extend(c);
221fd95acc6SHenry Wang         self.read_count += c.len() as u32;
222fd95acc6SHenry Wang         self.flags &= !PL011_FLAG_RXFE;
223fd95acc6SHenry Wang 
224fd95acc6SHenry Wang         if ((self.lcr & 0x10) == 0) || (self.read_count == 16) {
225fd95acc6SHenry Wang             self.flags |= PL011_FLAG_RXFF;
226fd95acc6SHenry Wang         }
227fd95acc6SHenry Wang 
228fd95acc6SHenry Wang         if self.read_count >= self.read_trigger {
229fd95acc6SHenry Wang             self.int_level |= PL011_INT_RX;
230fd95acc6SHenry Wang             self.trigger_interrupt()?;
231fd95acc6SHenry Wang         }
232fd95acc6SHenry Wang 
233fd95acc6SHenry Wang         Ok(())
234fd95acc6SHenry Wang     }
235fd95acc6SHenry Wang 
flush_output(&mut self) -> result::Result<(), io::Error>2360066ddefSWilliam Douglas     pub fn flush_output(&mut self) -> result::Result<(), io::Error> {
2370066ddefSWilliam Douglas         if let Some(out) = self.out.as_mut() {
2380066ddefSWilliam Douglas             out.flush()?;
2390066ddefSWilliam Douglas         }
2400066ddefSWilliam Douglas         Ok(())
2410066ddefSWilliam Douglas     }
2420066ddefSWilliam Douglas 
pl011_get_baudrate(&self) -> u32243fd95acc6SHenry Wang     fn pl011_get_baudrate(&self) -> u32 {
244fd95acc6SHenry Wang         if self.fbrd == 0 {
245fd95acc6SHenry Wang             return 0;
246fd95acc6SHenry Wang         }
247fd95acc6SHenry Wang 
248fd95acc6SHenry Wang         let clk = 24_000_000; // We set the APB_PLCK to 24M in device tree
249fd95acc6SHenry Wang         (clk / ((self.ibrd << 6) + self.fbrd)) << 2
250fd95acc6SHenry Wang     }
251fd95acc6SHenry Wang 
pl011_trace_baudrate_change(&self)252fd95acc6SHenry Wang     fn pl011_trace_baudrate_change(&self) {
253fd95acc6SHenry Wang         debug!(
254fd95acc6SHenry Wang             "=== New baudrate: {:#?} (clk: {:#?}Hz, ibrd: {:#?}, fbrd: {:#?}) ===",
255fd95acc6SHenry Wang             self.pl011_get_baudrate(),
256fd95acc6SHenry Wang             24_000_000, // We set the APB_PLCK to 24M in device tree
257fd95acc6SHenry Wang             self.ibrd,
258fd95acc6SHenry Wang             self.fbrd
259fd95acc6SHenry Wang         );
260fd95acc6SHenry Wang     }
261fd95acc6SHenry Wang 
pl011_set_read_trigger(&mut self)262fd95acc6SHenry Wang     fn pl011_set_read_trigger(&mut self) {
263fd95acc6SHenry Wang         self.read_trigger = 1;
264fd95acc6SHenry Wang     }
265fd95acc6SHenry Wang 
handle_write(&mut self, offset: u64, val: u32) -> Result<()>266fd95acc6SHenry Wang     fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
267fd95acc6SHenry Wang         match offset >> 2 {
268fd95acc6SHenry Wang             UARTDR => {
269fd95acc6SHenry Wang                 self.int_level |= PL011_INT_TX;
270fd95acc6SHenry Wang                 if let Some(out) = self.out.as_mut() {
271fd95acc6SHenry Wang                     out.write_all(&[val.to_le_bytes()[0]])
272fd95acc6SHenry Wang                         .map_err(Error::WriteAllFailure)?;
273fd95acc6SHenry Wang                     out.flush().map_err(Error::FlushFailure)?;
274fd95acc6SHenry Wang                 }
275fd95acc6SHenry Wang             }
276fd95acc6SHenry Wang             UARTRSR_UARTECR => {
277fd95acc6SHenry Wang                 self.rsr = 0;
278fd95acc6SHenry Wang             }
279fd95acc6SHenry Wang             UARTFR => { /* Writes to Flag register are ignored.*/ }
280fd95acc6SHenry Wang             UARTILPR => {
281fd95acc6SHenry Wang                 self.ilpr = val;
282fd95acc6SHenry Wang             }
283fd95acc6SHenry Wang             UARTIBRD => {
284fd95acc6SHenry Wang                 self.ibrd = val;
285fd95acc6SHenry Wang                 self.pl011_trace_baudrate_change();
286fd95acc6SHenry Wang             }
287fd95acc6SHenry Wang             UARTFBRD => {
288fd95acc6SHenry Wang                 self.fbrd = val;
289fd95acc6SHenry Wang                 self.pl011_trace_baudrate_change();
290fd95acc6SHenry Wang             }
291fd95acc6SHenry Wang             UARTLCR_H => {
292fd95acc6SHenry Wang                 /* Reset the FIFO state on FIFO enable or disable */
293fd95acc6SHenry Wang                 if ((self.lcr ^ val) & 0x10) != 0 {
294fd95acc6SHenry Wang                     self.read_count = 0;
295fd95acc6SHenry Wang                 }
296fd95acc6SHenry Wang                 self.lcr = val;
297fd95acc6SHenry Wang                 self.pl011_set_read_trigger();
298fd95acc6SHenry Wang             }
299fd95acc6SHenry Wang             UARTCR => {
300fd95acc6SHenry Wang                 self.cr = val;
301fd95acc6SHenry Wang             }
302fd95acc6SHenry Wang             UARTIFLS => {
303fd95acc6SHenry Wang                 self.ifl = val;
304fd95acc6SHenry Wang                 self.pl011_set_read_trigger();
305fd95acc6SHenry Wang             }
306fd95acc6SHenry Wang             UARTIMSC => {
307fd95acc6SHenry Wang                 self.int_enabled = val;
308fd95acc6SHenry Wang                 self.trigger_interrupt().map_err(Error::InterruptFailure)?;
309fd95acc6SHenry Wang             }
310fd95acc6SHenry Wang             UARTICR => {
311fd95acc6SHenry Wang                 self.int_level &= !val;
312fd95acc6SHenry Wang                 self.trigger_interrupt().map_err(Error::InterruptFailure)?;
313fd95acc6SHenry Wang             }
314fd95acc6SHenry Wang             UARTDMACR => {
315fd95acc6SHenry Wang                 self.dmacr = val;
316fd95acc6SHenry Wang                 if (val & 3) != 0 {
31740da6210SRob Bradford                     return Err(Error::DmaNotImplemented);
318fd95acc6SHenry Wang                 }
319fd95acc6SHenry Wang             }
3206dbc1362SJianyong Wu             UARTDEBUG => {
3216dbc1362SJianyong Wu                 self.debug = val;
3226dbc1362SJianyong Wu                 self.handle_debug();
3236dbc1362SJianyong Wu             }
324fd95acc6SHenry Wang             off => {
3256dbc1362SJianyong Wu                 debug!("PL011: Bad write offset, offset: {}", off);
326fd95acc6SHenry Wang                 return Err(Error::BadWriteOffset(off));
327fd95acc6SHenry Wang             }
328fd95acc6SHenry Wang         }
329fd95acc6SHenry Wang         Ok(())
330fd95acc6SHenry Wang     }
331fd95acc6SHenry Wang 
handle_debug(&self)3326dbc1362SJianyong Wu     fn handle_debug(&self) {
3336dbc1362SJianyong Wu         let elapsed = self.timestamp.elapsed();
3346dbc1362SJianyong Wu 
3356dbc1362SJianyong Wu         match self.debug {
33619b006ebSRob Bradford             0x00..=0x1f => warn!(
3376dbc1362SJianyong Wu                 "[Debug I/O port: Firmware code: 0x{:x}] {}.{:>06} seconds",
3386dbc1362SJianyong Wu                 self.debug,
3396dbc1362SJianyong Wu                 elapsed.as_secs(),
3406dbc1362SJianyong Wu                 elapsed.as_micros()
3416dbc1362SJianyong Wu             ),
34219b006ebSRob Bradford             0x20..=0x3f => warn!(
3436dbc1362SJianyong Wu                 "[Debug I/O port: Bootloader code: 0x{:x}] {}.{:>06} seconds",
3446dbc1362SJianyong Wu                 self.debug,
3456dbc1362SJianyong Wu                 elapsed.as_secs(),
3466dbc1362SJianyong Wu                 elapsed.as_micros()
3476dbc1362SJianyong Wu             ),
34819b006ebSRob Bradford             0x40..=0x5f => warn!(
3496dbc1362SJianyong Wu                 "[Debug I/O port: Kernel code: 0x{:x}] {}.{:>06} seconds",
3506dbc1362SJianyong Wu                 self.debug,
3516dbc1362SJianyong Wu                 elapsed.as_secs(),
3526dbc1362SJianyong Wu                 elapsed.as_micros()
3536dbc1362SJianyong Wu             ),
35419b006ebSRob Bradford             0x60..=0x7f => warn!(
3556dbc1362SJianyong Wu                 "[Debug I/O port: Userspace code: 0x{:x}] {}.{:>06} seconds",
3566dbc1362SJianyong Wu                 self.debug,
3576dbc1362SJianyong Wu                 elapsed.as_secs(),
3586dbc1362SJianyong Wu                 elapsed.as_micros()
3596dbc1362SJianyong Wu             ),
3606dbc1362SJianyong Wu             _ => {}
3616dbc1362SJianyong Wu         }
3626dbc1362SJianyong Wu     }
3636dbc1362SJianyong Wu 
trigger_interrupt(&mut self) -> result::Result<(), io::Error>364fd95acc6SHenry Wang     fn trigger_interrupt(&mut self) -> result::Result<(), io::Error> {
365fd95acc6SHenry Wang         self.irq.trigger(0)
366fd95acc6SHenry Wang     }
367fd95acc6SHenry Wang }
368fd95acc6SHenry Wang 
36940da6210SRob Bradford impl BusDevice for Pl011 {
read(&mut self, _base: u64, offset: u64, data: &mut [u8])370fd95acc6SHenry Wang     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
371fd95acc6SHenry Wang         let mut read_ok = true;
3721dc91342SRob Bradford         let v = if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&(offset >> 2)) {
373fd95acc6SHenry Wang             let index = ((offset - 0xfe0) >> 2) as usize;
3741dc91342SRob Bradford             u32::from(PL011_ID[index])
375fd95acc6SHenry Wang         } else {
3761dc91342SRob Bradford             match offset >> 2 {
377fd95acc6SHenry Wang                 UARTDR => {
378fd95acc6SHenry Wang                     self.flags &= !PL011_FLAG_RXFF;
3791dc91342SRob Bradford                     let c: u32 = self.read_fifo.pop_front().unwrap_or_default().into();
380fd95acc6SHenry Wang                     if self.read_count > 0 {
381fd95acc6SHenry Wang                         self.read_count -= 1;
382fd95acc6SHenry Wang                     }
383fd95acc6SHenry Wang                     if self.read_count == 0 {
384fd95acc6SHenry Wang                         self.flags |= PL011_FLAG_RXFE;
385fd95acc6SHenry Wang                     }
386fd95acc6SHenry Wang                     if self.read_count == (self.read_trigger - 1) {
387fd95acc6SHenry Wang                         self.int_level &= !PL011_INT_RX;
388fd95acc6SHenry Wang                     }
389fd95acc6SHenry Wang                     self.rsr = c >> 8;
3901dc91342SRob Bradford                     c
391fd95acc6SHenry Wang                 }
392fd95acc6SHenry Wang                 UARTRSR_UARTECR => self.rsr,
393fd95acc6SHenry Wang                 UARTFR => self.flags,
394fd95acc6SHenry Wang                 UARTILPR => self.ilpr,
395fd95acc6SHenry Wang                 UARTIBRD => self.ibrd,
396fd95acc6SHenry Wang                 UARTFBRD => self.fbrd,
397fd95acc6SHenry Wang                 UARTLCR_H => self.lcr,
398fd95acc6SHenry Wang                 UARTCR => self.cr,
399fd95acc6SHenry Wang                 UARTIFLS => self.ifl,
400fd95acc6SHenry Wang                 UARTIMSC => self.int_enabled,
401fd95acc6SHenry Wang                 UARTRIS => self.int_level,
402f42c6d56SWei Liu                 UARTMIS => self.int_level & self.int_enabled,
403fd95acc6SHenry Wang                 UARTDMACR => self.dmacr,
4046dbc1362SJianyong Wu                 UARTDEBUG => self.debug,
405fd95acc6SHenry Wang                 _ => {
406fd95acc6SHenry Wang                     read_ok = false;
407fd95acc6SHenry Wang                     0
408fd95acc6SHenry Wang                 }
409fd95acc6SHenry Wang             }
4101dc91342SRob Bradford         };
411fd95acc6SHenry Wang 
412fd95acc6SHenry Wang         if read_ok && data.len() <= 4 {
413fd95acc6SHenry Wang             write_le_u32(data, v);
414fd95acc6SHenry Wang         } else {
415fd95acc6SHenry Wang             warn!(
416fd95acc6SHenry Wang                 "Invalid PL011 read: offset {}, data length {}",
417fd95acc6SHenry Wang                 offset,
418fd95acc6SHenry Wang                 data.len()
419fd95acc6SHenry Wang             );
420fd95acc6SHenry Wang         }
421fd95acc6SHenry Wang     }
422fd95acc6SHenry Wang 
write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>423fd95acc6SHenry Wang     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
424fd95acc6SHenry Wang         if data.len() <= 4 {
4255825ab2dSBo Chen             let v = read_le_u32(data);
426fd95acc6SHenry Wang             if let Err(e) = self.handle_write(offset, v) {
427fd95acc6SHenry Wang                 warn!("Failed to write to PL011 device: {}", e);
428fd95acc6SHenry Wang             }
429fd95acc6SHenry Wang         } else {
430fd95acc6SHenry Wang             warn!(
431fd95acc6SHenry Wang                 "Invalid PL011 write: offset {}, data length {}",
432fd95acc6SHenry Wang                 offset,
433fd95acc6SHenry Wang                 data.len()
434fd95acc6SHenry Wang             );
435fd95acc6SHenry Wang         }
436fd95acc6SHenry Wang 
437fd95acc6SHenry Wang         None
438fd95acc6SHenry Wang     }
439fd95acc6SHenry Wang }
440fd95acc6SHenry Wang 
44140da6210SRob Bradford impl Snapshottable for Pl011 {
id(&self) -> String442fd95acc6SHenry Wang     fn id(&self) -> String {
443fd95acc6SHenry Wang         self.id.clone()
444fd95acc6SHenry Wang     }
445fd95acc6SHenry Wang 
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>446fd95acc6SHenry Wang     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
44710ab87d6SRob Bradford         Snapshot::new_from_state(&self.state())
448fd95acc6SHenry Wang     }
449fd95acc6SHenry Wang }
450fd95acc6SHenry Wang 
45140da6210SRob Bradford impl Pausable for Pl011 {}
45240da6210SRob Bradford impl Transportable for Pl011 {}
45340da6210SRob Bradford impl Migratable for Pl011 {}
454fd95acc6SHenry Wang 
455fd95acc6SHenry Wang #[cfg(test)]
456fd95acc6SHenry Wang mod tests {
457f093ffcbSRob Bradford     use std::sync::Mutex;
45888a9f799SRob Bradford 
459fd95acc6SHenry Wang     use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
460fd95acc6SHenry Wang     use vmm_sys_util::eventfd::EventFd;
461fd95acc6SHenry Wang 
46288a9f799SRob Bradford     use super::*;
46388a9f799SRob Bradford 
464fd95acc6SHenry Wang     const SERIAL_NAME: &str = "serial";
465fd95acc6SHenry Wang 
466fd95acc6SHenry Wang     struct TestInterrupt {
467fd95acc6SHenry Wang         event_fd: EventFd,
468fd95acc6SHenry Wang     }
469fd95acc6SHenry Wang 
470fd95acc6SHenry Wang     impl InterruptSourceGroup for TestInterrupt {
trigger(&self, _index: InterruptIndex) -> result::Result<(), std::io::Error>471fd95acc6SHenry Wang         fn trigger(&self, _index: InterruptIndex) -> result::Result<(), std::io::Error> {
472fd95acc6SHenry Wang             self.event_fd.write(1)
473fd95acc6SHenry Wang         }
update( &self, _index: InterruptIndex, _config: InterruptSourceConfig, _masked: bool, _set_gsi: bool, ) -> result::Result<(), std::io::Error>474fd95acc6SHenry Wang         fn update(
475fd95acc6SHenry Wang             &self,
476fd95acc6SHenry Wang             _index: InterruptIndex,
477fd95acc6SHenry Wang             _config: InterruptSourceConfig,
478ed87e42eSRob Bradford             _masked: bool,
4790149e650SYong He             _set_gsi: bool,
480fd95acc6SHenry Wang         ) -> result::Result<(), std::io::Error> {
481fd95acc6SHenry Wang             Ok(())
482fd95acc6SHenry Wang         }
set_gsi(&self) -> result::Result<(), std::io::Error>4830149e650SYong He         fn set_gsi(&self) -> result::Result<(), std::io::Error> {
4840149e650SYong He             Ok(())
4850149e650SYong He         }
notifier(&self, _index: InterruptIndex) -> Option<EventFd>486fd95acc6SHenry Wang         fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
487fd95acc6SHenry Wang             Some(self.event_fd.try_clone().unwrap())
488fd95acc6SHenry Wang         }
489fd95acc6SHenry Wang     }
490fd95acc6SHenry Wang 
491fd95acc6SHenry Wang     impl TestInterrupt {
new(event_fd: EventFd) -> Self492fd95acc6SHenry Wang         fn new(event_fd: EventFd) -> Self {
493fd95acc6SHenry Wang             TestInterrupt { event_fd }
494fd95acc6SHenry Wang         }
495fd95acc6SHenry Wang     }
496fd95acc6SHenry Wang 
497fd95acc6SHenry Wang     #[derive(Clone)]
498fd95acc6SHenry Wang     struct SharedBuffer {
499fd95acc6SHenry Wang         buf: Arc<Mutex<Vec<u8>>>,
500fd95acc6SHenry Wang     }
501fd95acc6SHenry Wang 
502fd95acc6SHenry Wang     impl SharedBuffer {
new() -> SharedBuffer503fd95acc6SHenry Wang         fn new() -> SharedBuffer {
504fd95acc6SHenry Wang             SharedBuffer {
505fd95acc6SHenry Wang                 buf: Arc::new(Mutex::new(Vec::new())),
506fd95acc6SHenry Wang             }
507fd95acc6SHenry Wang         }
508fd95acc6SHenry Wang     }
509fd95acc6SHenry Wang 
510fd95acc6SHenry Wang     impl io::Write for SharedBuffer {
write(&mut self, buf: &[u8]) -> io::Result<usize>511fd95acc6SHenry Wang         fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
512fd95acc6SHenry Wang             self.buf.lock().unwrap().write(buf)
513fd95acc6SHenry Wang         }
flush(&mut self) -> io::Result<()>514fd95acc6SHenry Wang         fn flush(&mut self) -> io::Result<()> {
515fd95acc6SHenry Wang             self.buf.lock().unwrap().flush()
516fd95acc6SHenry Wang         }
517fd95acc6SHenry Wang     }
518fd95acc6SHenry Wang 
519fd95acc6SHenry Wang     #[test]
pl011_output()520fd95acc6SHenry Wang     fn pl011_output() {
521fd95acc6SHenry Wang         let intr_evt = EventFd::new(0).unwrap();
522fd95acc6SHenry Wang         let pl011_out = SharedBuffer::new();
52340da6210SRob Bradford         let mut pl011 = Pl011::new(
524fd95acc6SHenry Wang             String::from(SERIAL_NAME),
525dcc646f5SSebastien Boeuf             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
526fd95acc6SHenry Wang             Some(Box::new(pl011_out.clone())),
527707cea21SRob Bradford             Instant::now(),
5289fbf52b9SSebastien Boeuf             None,
529fd95acc6SHenry Wang         );
530fd95acc6SHenry Wang 
5318aa2d7abSWei Liu         pl011.write(0, UARTDR, b"xy");
5328aa2d7abSWei Liu         pl011.write(0, UARTDR, b"a");
5338aa2d7abSWei Liu         pl011.write(0, UARTDR, b"b");
5348aa2d7abSWei Liu         pl011.write(0, UARTDR, b"c");
5358aa2d7abSWei Liu         assert_eq!(pl011_out.buf.lock().unwrap().as_slice(), b"xabc");
536fd95acc6SHenry Wang     }
537fd95acc6SHenry Wang 
538fd95acc6SHenry Wang     #[test]
pl011_input()539fd95acc6SHenry Wang     fn pl011_input() {
540fd95acc6SHenry Wang         let intr_evt = EventFd::new(0).unwrap();
541fd95acc6SHenry Wang         let pl011_out = SharedBuffer::new();
54240da6210SRob Bradford         let mut pl011 = Pl011::new(
543fd95acc6SHenry Wang             String::from(SERIAL_NAME),
544dcc646f5SSebastien Boeuf             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
545fd95acc6SHenry Wang             Some(Box::new(pl011_out)),
546707cea21SRob Bradford             Instant::now(),
5479fbf52b9SSebastien Boeuf             None,
548fd95acc6SHenry Wang         );
549fd95acc6SHenry Wang 
550fd95acc6SHenry Wang         // write 1 to the interrupt event fd, so that read doesn't block in case the event fd
551fd95acc6SHenry Wang         // counter doesn't change (for 0 it blocks)
552297236a7SRuoqing He         intr_evt.write(1).unwrap();
5538aa2d7abSWei Liu         pl011.queue_input_bytes(b"abc").unwrap();
554fd95acc6SHenry Wang 
555fd95acc6SHenry Wang         assert_eq!(intr_evt.read().unwrap(), 2);
556fd95acc6SHenry Wang 
557fd95acc6SHenry Wang         let mut data = [0u8];
5583888f576SRob Bradford         pl011.read(0, UARTDR, &mut data);
559fd95acc6SHenry Wang         assert_eq!(data[0], b'a');
5603888f576SRob Bradford         pl011.read(0, UARTDR, &mut data);
561fd95acc6SHenry Wang         assert_eq!(data[0], b'b');
5623888f576SRob Bradford         pl011.read(0, UARTDR, &mut data);
563fd95acc6SHenry Wang         assert_eq!(data[0], b'c');
564fd95acc6SHenry Wang     }
565fd95acc6SHenry Wang }
566