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