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