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