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