xref: /cloud-hypervisor/devices/src/legacy/gpio_pl061.rs (revision f7f2f25a574b1b2dba22c094fc8226d404157d15)
1 // Copyright 2021 Arm Limited (or its affiliates). All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 
5 //! ARM PrimeCell General Purpose Input/Output(PL061)
6 //!
7 //! This module implements an ARM PrimeCell General Purpose Input/Output(PL061) to support gracefully poweroff microvm from external.
8 //!
9 
10 use crate::{read_le_u32, write_le_u32};
11 use std::result;
12 use std::sync::{Arc, Barrier};
13 use std::{fmt, io};
14 use versionize::{VersionMap, Versionize, VersionizeResult};
15 use versionize_derive::Versionize;
16 use vm_device::interrupt::InterruptSourceGroup;
17 use vm_device::BusDevice;
18 use vm_migration::{
19     Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
20 };
21 
22 const OFS_DATA: u64 = 0x400; // Data Register
23 const GPIODIR: u64 = 0x400; // Direction Register
24 const GPIOIS: u64 = 0x404; // Interrupt Sense Register
25 const GPIOIBE: u64 = 0x408; // Interrupt Both Edges Register
26 const GPIOIEV: u64 = 0x40c; // Interrupt Event Register
27 const GPIOIE: u64 = 0x410; // Interrupt Mask Register
28 const GPIORIE: u64 = 0x414; // Raw Interrupt Status Register
29 const GPIOMIS: u64 = 0x418; // Masked Interrupt Status Register
30 const GPIOIC: u64 = 0x41c; // Interrupt Clear Register
31 const GPIOAFSEL: u64 = 0x420; // Mode Control Select Register
32                               // From 0x424 to 0xFDC => reserved space.
33                               // From 0xFE0 to 0xFFC => Peripheral and PrimeCell Identification Registers which are Read Only registers.
34                               // Thses registers can conceptually be treated as a 32-bit register, and PartNumber[11:0] is used to identify the peripheral.
35                               // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
36 const GPIO_ID: [u8; 8] = [0x61, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
37 // ID Margins
38 const GPIO_ID_LOW: u64 = 0xfe0;
39 const GPIO_ID_HIGH: u64 = 0x1000;
40 
41 const N_GPIOS: u32 = 8;
42 
43 #[derive(Debug)]
44 pub enum Error {
45     BadWriteOffset(u64),
46     GpioInterruptDisabled,
47     GpioInterruptFailure(io::Error),
48     GpioTriggerKeyFailure(u32),
49 }
50 
51 impl fmt::Display for Error {
52     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53         match self {
54             Error::BadWriteOffset(offset) => write!(f, "Bad Write Offset: {}", offset),
55             Error::GpioInterruptDisabled => write!(f, "GPIO interrupt disabled by guest driver.",),
56             Error::GpioInterruptFailure(ref e) => {
57                 write!(f, "Could not trigger GPIO interrupt: {}.", e)
58             }
59             Error::GpioTriggerKeyFailure(key) => {
60                 write!(f, "Invalid GPIO Input key triggerd: {}.", key)
61             }
62         }
63     }
64 }
65 
66 type Result<T> = result::Result<T, Error>;
67 
68 /// A GPIO device following the PL061 specification.
69 pub struct Gpio {
70     id: String,
71     // Data Register
72     data: u32,
73     old_in_data: u32,
74     // Direction Register
75     dir: u32,
76     // Interrupt Sense Register
77     isense: u32,
78     // Interrupt Both Edges Register
79     ibe: u32,
80     // Interrupt Event Register
81     iev: u32,
82     // Interrupt Mask Register
83     im: u32,
84     // Raw Interrupt Status Register
85     istate: u32,
86     // Mode Control Select Register
87     afsel: u32,
88     // GPIO irq_field
89     interrupt: Arc<dyn InterruptSourceGroup>,
90 }
91 
92 #[derive(Versionize)]
93 pub struct GpioState {
94     data: u32,
95     old_in_data: u32,
96     dir: u32,
97     isense: u32,
98     ibe: u32,
99     iev: u32,
100     im: u32,
101     istate: u32,
102     afsel: u32,
103 }
104 
105 impl VersionMapped for GpioState {}
106 
107 impl Gpio {
108     /// Constructs an PL061 GPIO device.
109     pub fn new(id: String, interrupt: Arc<dyn InterruptSourceGroup>) -> Self {
110         Self {
111             id,
112             data: 0,
113             old_in_data: 0,
114             dir: 0,
115             isense: 0,
116             ibe: 0,
117             iev: 0,
118             im: 0,
119             istate: 0,
120             afsel: 0,
121             interrupt,
122         }
123     }
124 
125     fn state(&self) -> GpioState {
126         GpioState {
127             data: self.data,
128             old_in_data: self.old_in_data,
129             dir: self.dir,
130             isense: self.isense,
131             ibe: self.ibe,
132             iev: self.iev,
133             im: self.im,
134             istate: self.istate,
135             afsel: self.afsel,
136         }
137     }
138 
139     fn set_state(&mut self, state: &GpioState) {
140         self.data = state.data;
141         self.old_in_data = state.old_in_data;
142         self.dir = state.dir;
143         self.isense = state.isense;
144         self.ibe = state.ibe;
145         self.iev = state.iev;
146         self.im = state.im;
147         self.istate = state.istate;
148         self.afsel = state.afsel;
149     }
150 
151     fn pl061_internal_update(&mut self) {
152         // FIXME:
153         //  Missing Output Interrupt Emulation.
154 
155         // Input Edging Interrupt Emulation.
156         let changed = ((self.old_in_data ^ self.data) & !self.dir) as u32;
157         if changed > 0 {
158             self.old_in_data = self.data;
159             for i in 0..N_GPIOS {
160                 let mask = (1 << i) as u32;
161                 if (changed & mask) > 0 {
162                     // Bits set high in GPIOIS(Interrupt sense register) configure the corresponding
163                     // pins to detect levels, otherwise, detect edges.
164                     if (self.isense & mask) == 0 {
165                         if (self.ibe & mask) > 0 {
166                             // Bits set high in GPIOIBE(Interrupt both-edges register) configure the corresponding
167                             // pins to detect both falling and rising edges.
168                             // Clearing a bit configures the pin to be controlled by GPIOIEV.
169                             self.istate |= mask;
170                         } else {
171                             // Bits set to high in GPIOIEV(Interrupt event register) configure the
172                             // corresponding pin to detect rising edges, otherwise, detect falling edges.
173                             self.istate |= !(self.data ^ self.iev) & mask;
174                         }
175                     }
176                 }
177             }
178         }
179 
180         // Input Level Interrupt Emulation.
181         self.istate |= !(self.data ^ self.iev) & self.isense;
182     }
183 
184     fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
185         if offset < OFS_DATA {
186             // In order to write to data register, the corresponding bits in the mask, resulting
187             // from the offsite[9:2], must be HIGH. otherwise the bit values remain unchanged.
188             let mask = (offset >> 2) as u32 & self.dir;
189             self.data = (self.data & !mask) | (val & mask);
190         } else {
191             match offset {
192                 GPIODIR => {
193                     /* Direction Register */
194                     self.dir = val & 0xff;
195                 }
196                 GPIOIS => {
197                     /* Interrupt Sense Register */
198                     self.isense = val & 0xff;
199                 }
200                 GPIOIBE => {
201                     /* Interrupt Both Edges Register */
202                     self.ibe = val & 0xff;
203                 }
204                 GPIOIEV => {
205                     /* Interrupt Event Register */
206                     self.iev = val & 0xff;
207                 }
208                 GPIOIE => {
209                     /* Interrupt Mask Register */
210                     self.im = val & 0xff;
211                 }
212                 GPIOIC => {
213                     /* Interrupt Clear Register */
214                     self.istate &= !val;
215                 }
216                 GPIOAFSEL => {
217                     /* Mode Control Select Register */
218                     self.afsel = val & 0xff;
219                 }
220                 o => {
221                     return Err(Error::BadWriteOffset(o));
222                 }
223             }
224         }
225         Ok(())
226     }
227 
228     pub fn trigger_key(&mut self, key: u32) -> Result<()> {
229         let mask = (1 << key) as u32;
230         if (!self.dir & mask) > 0 {
231             // emulate key event
232             // By default, Input Pin is configured to detect both rising and falling edges.
233             // So reverse the input pin data to generate a pulse.
234             self.data |= !(self.data & mask) & mask;
235             self.pl061_internal_update();
236 
237             match self.trigger_gpio_interrupt() {
238                 Ok(_) | Err(Error::GpioInterruptDisabled) => return Ok(()),
239                 Err(e) => return Err(e),
240             }
241         }
242 
243         Err(Error::GpioTriggerKeyFailure(key))
244     }
245 
246     fn trigger_gpio_interrupt(&self) -> Result<()> {
247         // Bits set to high in GPIOIE(Interrupt mask register) allow the corresponding pins to
248         // trigger their individual interrupts and then the combined GPIOINTR line.
249         if (self.istate & self.im) == 0 {
250             warn!("Failed to trigger GPIO input interrupt (disabled by guest OS)");
251             return Err(Error::GpioInterruptDisabled);
252         }
253         self.interrupt
254             .trigger(0)
255             .map_err(Error::GpioInterruptFailure)?;
256         Ok(())
257     }
258 }
259 
260 impl BusDevice for Gpio {
261     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
262         let value;
263         let mut read_ok = true;
264 
265         if (GPIO_ID_LOW..GPIO_ID_HIGH).contains(&offset) {
266             let index = ((offset - GPIO_ID_LOW) >> 2) as usize;
267             value = u32::from(GPIO_ID[index]);
268         } else if offset < OFS_DATA {
269             value = self.data & ((offset >> 2) as u32)
270         } else {
271             value = match offset {
272                 GPIODIR => self.dir,
273                 GPIOIS => self.isense,
274                 GPIOIBE => self.ibe,
275                 GPIOIEV => self.iev,
276                 GPIOIE => self.im,
277                 GPIORIE => self.istate,
278                 GPIOMIS => self.istate & self.im,
279                 GPIOAFSEL => self.afsel,
280                 _ => {
281                     read_ok = false;
282                     0
283                 }
284             };
285         }
286 
287         if read_ok && data.len() <= 4 {
288             write_le_u32(data, value);
289         } else {
290             warn!(
291                 "Invalid GPIO PL061 read: offset {}, data length {}",
292                 offset,
293                 data.len()
294             );
295         }
296     }
297 
298     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
299         if data.len() <= 4 {
300             let value = read_le_u32(data);
301             if let Err(e) = self.handle_write(offset, value) {
302                 warn!("Failed to write to GPIO PL061 device: {}", e);
303             }
304         } else {
305             warn!(
306                 "Invalid GPIO PL061 write: offset {}, data length {}",
307                 offset,
308                 data.len()
309             );
310         }
311 
312         None
313     }
314 }
315 
316 impl Snapshottable for Gpio {
317     fn id(&self) -> String {
318         self.id.clone()
319     }
320 
321     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
322         Snapshot::new_from_versioned_state(&self.id, &self.state())
323     }
324 
325     fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
326         self.set_state(&snapshot.to_versioned_state(&self.id)?);
327         Ok(())
328     }
329 }
330 
331 impl Pausable for Gpio {}
332 impl Transportable for Gpio {}
333 impl Migratable for Gpio {}
334 
335 #[cfg(test)]
336 mod tests {
337     use super::*;
338     use crate::{read_le_u32, write_le_u32};
339     use std::sync::Arc;
340     use vm_device::interrupt::{InterruptIndex, InterruptSourceConfig};
341     use vmm_sys_util::eventfd::EventFd;
342 
343     const GPIO_NAME: &str = "gpio";
344     const LEGACY_GPIO_MAPPED_IO_START: u64 = 0x0902_0000;
345 
346     struct TestInterrupt {
347         event_fd: EventFd,
348     }
349 
350     impl InterruptSourceGroup for TestInterrupt {
351         fn trigger(&self, _index: InterruptIndex) -> result::Result<(), std::io::Error> {
352             self.event_fd.write(1)
353         }
354 
355         fn update(
356             &self,
357             _index: InterruptIndex,
358             _config: InterruptSourceConfig,
359         ) -> result::Result<(), std::io::Error> {
360             Ok(())
361         }
362 
363         fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
364             Some(self.event_fd.try_clone().unwrap())
365         }
366     }
367 
368     impl TestInterrupt {
369         fn new(event_fd: EventFd) -> Self {
370             TestInterrupt { event_fd }
371         }
372     }
373 
374     #[test]
375     fn test_gpio_read_write_and_event() {
376         let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
377         let mut gpio = Gpio::new(
378             String::from(GPIO_NAME),
379             Arc::new(TestInterrupt::new(intr_evt.try_clone().unwrap())),
380         );
381         let mut data = [0; 4];
382 
383         // Read and write to the GPIODIR register.
384         // Set pin 0 output pin.
385         write_le_u32(&mut data, 1);
386         gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &data);
387         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIODIR, &mut data);
388         let v = read_le_u32(&data);
389         assert_eq!(v, 1);
390 
391         // Read and write to the GPIODATA register.
392         write_le_u32(&mut data, 1);
393         // Set pin 0 high.
394         let offset = 0x00000004_u64;
395         gpio.write(LEGACY_GPIO_MAPPED_IO_START, offset, &data);
396         gpio.read(LEGACY_GPIO_MAPPED_IO_START, offset, &mut data);
397         let v = read_le_u32(&data);
398         assert_eq!(v, 1);
399 
400         // Read and write to the GPIOIS register.
401         // Configure pin 0 detecting level interrupt.
402         write_le_u32(&mut data, 1);
403         gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &data);
404         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIS, &mut data);
405         let v = read_le_u32(&data);
406         assert_eq!(v, 1);
407 
408         // Read and write to the GPIOIBE register.
409         // Configure pin 1 detecting both falling and rising edges.
410         write_le_u32(&mut data, 2);
411         gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &data);
412         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIBE, &mut data);
413         let v = read_le_u32(&data);
414         assert_eq!(v, 2);
415 
416         // Read and write to the GPIOIEV register.
417         // Configure pin 2 detecting both falling and rising edges.
418         write_le_u32(&mut data, 4);
419         gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &data);
420         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIEV, &mut data);
421         let v = read_le_u32(&data);
422         assert_eq!(v, 4);
423 
424         // Read and write to the GPIOIE register.
425         // Configure pin 0...2 capable of triggering their individual interrupts
426         // and then the combined GPIOINTR line.
427         write_le_u32(&mut data, 7);
428         gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &data);
429         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIE, &mut data);
430         let v = read_le_u32(&data);
431         assert_eq!(v, 7);
432 
433         let mask = 0x00000002_u32;
434         // emulate an rising pulse in pin 1.
435         gpio.data |= !(gpio.data & mask) & mask;
436         gpio.pl061_internal_update();
437         // The interrupt line on pin 1 should be on.
438         // Read the GPIOMIS register.
439         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOMIS, &mut data);
440         let v = read_le_u32(&data);
441         assert_eq!(v, 2);
442 
443         // Read and Write to the GPIOIC register.
444         // clear interrupt in pin 1.
445         write_le_u32(&mut data, 2);
446         gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &data);
447         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIOIC, &mut data);
448         let v = read_le_u32(&data);
449         assert_eq!(v, 2);
450 
451         // Attempts to write beyond the writable space.
452         write_le_u32(&mut data, 0);
453         gpio.write(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &data);
454 
455         let mut data = [0; 4];
456         gpio.read(LEGACY_GPIO_MAPPED_IO_START, GPIO_ID_LOW, &mut data);
457         let index = GPIO_ID_LOW + 3;
458         assert_eq!(data[0], GPIO_ID[((index - GPIO_ID_LOW) >> 2) as usize]);
459     }
460 }
461