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