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