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