1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // Copyright © 2019 Intel Corporation 6 // 7 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 8 // 9 // Implementation of an intel 82093AA Input/Output Advanced Programmable Interrupt Controller 10 // See https://pdos.csail.mit.edu/6.828/2016/readings/ia32/ioapic.pdf for a specification. 11 12 use super::interrupt_controller::{Error, InterruptController}; 13 use anyhow::anyhow; 14 use byteorder::{ByteOrder, LittleEndian}; 15 use std::result; 16 use std::sync::{Arc, Barrier}; 17 use versionize::{VersionMap, Versionize, VersionizeResult}; 18 use versionize_derive::Versionize; 19 use vm_device::interrupt::{ 20 InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup, 21 MsiIrqGroupConfig, MsiIrqSourceConfig, 22 }; 23 use vm_device::BusDevice; 24 use vm_memory::GuestAddress; 25 use vm_migration::{ 26 Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped, 27 }; 28 use vmm_sys_util::eventfd::EventFd; 29 30 type Result<T> = result::Result<T, Error>; 31 32 // I/O REDIRECTION TABLE REGISTER 33 // 34 // There are 24 I/O Redirection Table entry registers. Each register is a 35 // dedicated entry for each interrupt input signal. Each register is 64 bits 36 // split between two 32 bits registers as follow: 37 // 38 // 63-56: Destination Field - R/W 39 // 55-17: Reserved 40 // 16: Interrupt Mask - R/W 41 // 15: Trigger Mode - R/W 42 // 14: Remote IRR - RO 43 // 13: Interrupt Input Pin Polarity - R/W 44 // 12: Delivery Status - RO 45 // 11: Destination Mode - R/W 46 // 10-8: Delivery Mode - R/W 47 // 7-0: Interrupt Vector - R/W 48 pub type RedirectionTableEntry = u64; 49 50 fn vector(entry: RedirectionTableEntry) -> u8 { 51 (entry & 0xffu64) as u8 52 } 53 fn delivery_mode(entry: RedirectionTableEntry) -> u8 { 54 ((entry >> 8) & 0x7u64) as u8 55 } 56 fn destination_mode(entry: RedirectionTableEntry) -> u8 { 57 ((entry >> 11) & 0x1u64) as u8 58 } 59 fn remote_irr(entry: RedirectionTableEntry) -> u8 { 60 ((entry >> 14) & 0x1u64) as u8 61 } 62 fn trigger_mode(entry: RedirectionTableEntry) -> u8 { 63 ((entry >> 15) & 0x1u64) as u8 64 } 65 fn interrupt_mask(entry: RedirectionTableEntry) -> u8 { 66 ((entry >> 16) & 0x1u64) as u8 67 } 68 fn destination_field(entry: RedirectionTableEntry) -> u8 { 69 // When the destination mode is physical, the destination field should only 70 // be defined through bits 56-59, as defined in the IOAPIC specification. 71 // But from the APIC specification, the APIC ID is always defined on 8 bits 72 // no matter which destination mode is selected. That's why we always 73 // retrieve the destination field based on bits 56-63. 74 ((entry >> 56) & 0xffu64) as u8 75 } 76 fn set_delivery_status(entry: &mut RedirectionTableEntry, val: u8) { 77 // Clear bit 12 78 *entry &= 0xffff_ffff_ffff_efff; 79 // Set it with the expected value 80 *entry |= u64::from(val & 0x1) << 12; 81 } 82 fn set_remote_irr(entry: &mut RedirectionTableEntry, val: u8) { 83 // Clear bit 14 84 *entry &= 0xffff_ffff_ffff_bfff; 85 // Set it with the expected value 86 *entry |= u64::from(val & 0x1) << 14; 87 } 88 89 pub const NUM_IOAPIC_PINS: usize = 24; 90 const IOAPIC_VERSION_ID: u32 = 0x0017_0011; 91 92 // Constants for IOAPIC direct register offset 93 const IOAPIC_REG_ID: u8 = 0x00; 94 const IOAPIC_REG_VERSION: u8 = 0x01; 95 const IOAPIC_REG_ARBITRATION_ID: u8 = 0x02; 96 97 // Register offsets 98 const IOREGSEL_OFF: u8 = 0x0; 99 const IOWIN_OFF: u8 = 0x10; 100 const IOWIN_SCALE: u8 = 0x2; 101 const REG_MAX_OFFSET: u8 = IOWIN_OFF + (NUM_IOAPIC_PINS as u8 * 2) - 1; 102 103 #[repr(u8)] 104 enum TriggerMode { 105 Edge = 0, 106 Level = 1, 107 } 108 109 #[repr(u8)] 110 enum DeliveryMode { 111 Fixed = 0b000, 112 Lowest = 0b001, 113 Smi = 0b010, // System management interrupt 114 RemoteRead = 0b011, // This is no longer supported by intel. 115 Nmi = 0b100, // Non maskable interrupt 116 Init = 0b101, 117 Startup = 0b110, 118 External = 0b111, 119 } 120 121 /// Given an offset that was read from/written to, return a tuple of the relevant IRQ and whether 122 /// the offset refers to the high bits of that register. 123 fn decode_irq_from_selector(selector: u8) -> (usize, bool) { 124 ( 125 ((selector - IOWIN_OFF) / IOWIN_SCALE) as usize, 126 selector & 1 != 0, 127 ) 128 } 129 130 pub struct Ioapic { 131 id: String, 132 id_reg: u32, 133 reg_sel: u32, 134 reg_entries: [RedirectionTableEntry; NUM_IOAPIC_PINS], 135 used_entries: [bool; NUM_IOAPIC_PINS], 136 apic_address: GuestAddress, 137 interrupt_source_group: Arc<dyn InterruptSourceGroup>, 138 } 139 140 #[derive(Versionize)] 141 pub struct IoapicState { 142 id_reg: u32, 143 reg_sel: u32, 144 reg_entries: [RedirectionTableEntry; NUM_IOAPIC_PINS], 145 used_entries: [bool; NUM_IOAPIC_PINS], 146 apic_address: u64, 147 } 148 impl VersionMapped for IoapicState {} 149 150 impl BusDevice for Ioapic { 151 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) { 152 if data.len() != std::mem::size_of::<u32>() { 153 warn!("Invalid read size on IOAPIC: {}", data.len()); 154 return; 155 } 156 157 debug!("IOAPIC_R @ offset 0x{:x}", offset); 158 159 let value: u32 = match offset as u8 { 160 IOREGSEL_OFF => self.reg_sel, 161 IOWIN_OFF => self.ioapic_read(), 162 _ => { 163 error!("IOAPIC: failed reading at offset {}", offset); 164 return; 165 } 166 }; 167 168 LittleEndian::write_u32(data, value); 169 } 170 171 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> { 172 if data.len() != std::mem::size_of::<u32>() { 173 warn!("Invalid write size on IOAPIC: {}", data.len()); 174 return None; 175 } 176 177 debug!("IOAPIC_W @ offset 0x{:x}", offset); 178 179 let value = LittleEndian::read_u32(data); 180 181 match offset as u8 { 182 IOREGSEL_OFF => self.reg_sel = value, 183 IOWIN_OFF => self.ioapic_write(value), 184 _ => { 185 error!("IOAPIC: failed writing at offset {}", offset); 186 } 187 } 188 None 189 } 190 } 191 192 impl Ioapic { 193 pub fn new( 194 id: String, 195 apic_address: GuestAddress, 196 interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>, 197 ) -> Result<Ioapic> { 198 let interrupt_source_group = interrupt_manager 199 .create_group(MsiIrqGroupConfig { 200 base: 0, 201 count: NUM_IOAPIC_PINS as InterruptIndex, 202 }) 203 .map_err(Error::CreateInterruptSourceGroup)?; 204 205 // The IOAPIC is created with entries already masked. The guest will be 206 // in charge of unmasking them if/when necessary. 207 Ok(Ioapic { 208 id, 209 id_reg: 0, 210 reg_sel: 0, 211 reg_entries: [0x10000; NUM_IOAPIC_PINS], 212 used_entries: [false; NUM_IOAPIC_PINS], 213 apic_address, 214 interrupt_source_group, 215 }) 216 } 217 218 fn ioapic_write(&mut self, val: u32) { 219 debug!("IOAPIC_W reg 0x{:x}, val 0x{:x}", self.reg_sel, val); 220 221 match self.reg_sel as u8 { 222 IOAPIC_REG_VERSION => { 223 if val == 0 { 224 // Windows writes zero here (see #1791) 225 } else { 226 error!( 227 "IOAPIC: invalid write to version register (0x{:x}): 0x{:x}", 228 self.reg_sel, val 229 ); 230 } 231 } 232 IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf, 233 IOWIN_OFF..=REG_MAX_OFFSET => { 234 let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8); 235 if index > NUM_IOAPIC_PINS { 236 warn!("IOAPIC index out of range: {}", index); 237 return; 238 } 239 if is_high_bits { 240 self.reg_entries[index] &= 0xffff_ffff; 241 self.reg_entries[index] |= u64::from(val) << 32; 242 } else { 243 // Ensure not to override read-only bits: 244 // - Delivery Status (bit 12) 245 // - Remote IRR (bit 14) 246 self.reg_entries[index] &= 0xffff_ffff_0000_5000; 247 self.reg_entries[index] |= u64::from(val) & 0xffff_afff; 248 } 249 // The entry must be updated through the interrupt source 250 // group. 251 if let Err(e) = self.update_entry(index) { 252 error!("Failed updating IOAPIC entry: {:?}", e); 253 } 254 // Store the information this IRQ is now being used. 255 self.used_entries[index] = true; 256 } 257 _ => error!( 258 "IOAPIC: invalid write to register offset 0x{:x}", 259 self.reg_sel 260 ), 261 } 262 } 263 264 fn ioapic_read(&self) -> u32 { 265 debug!("IOAPIC_R reg 0x{:x}", self.reg_sel); 266 267 match self.reg_sel as u8 { 268 IOAPIC_REG_VERSION => IOAPIC_VERSION_ID, 269 IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24, 270 IOWIN_OFF..=REG_MAX_OFFSET => { 271 let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8); 272 if index > NUM_IOAPIC_PINS { 273 warn!("IOAPIC index out of range: {}", index); 274 return 0; 275 } 276 if is_high_bits { 277 (self.reg_entries[index] >> 32) as u32 278 } else { 279 (self.reg_entries[index] & 0xffff_ffff) as u32 280 } 281 } 282 _ => { 283 error!( 284 "IOAPIC: invalid read from register offset 0x{:x}", 285 self.reg_sel 286 ); 287 0 288 } 289 } 290 } 291 292 fn state(&self) -> IoapicState { 293 IoapicState { 294 id_reg: self.id_reg, 295 reg_sel: self.reg_sel, 296 reg_entries: self.reg_entries, 297 used_entries: self.used_entries, 298 apic_address: self.apic_address.0, 299 } 300 } 301 302 fn set_state(&mut self, state: &IoapicState) -> Result<()> { 303 self.id_reg = state.id_reg; 304 self.reg_sel = state.reg_sel; 305 self.reg_entries = state.reg_entries; 306 self.used_entries = state.used_entries; 307 self.apic_address = GuestAddress(state.apic_address); 308 for (irq, entry) in self.used_entries.iter().enumerate() { 309 if *entry { 310 self.update_entry(irq)?; 311 } 312 } 313 314 Ok(()) 315 } 316 317 fn update_entry(&self, irq: usize) -> Result<()> { 318 let entry = self.reg_entries[irq]; 319 320 // Validate Destination Mode value, and retrieve Destination ID 321 let destination_mode = destination_mode(entry); 322 let destination_id = destination_field(entry); 323 324 // When this bit is set, the message is directed to the processor with 325 // the lowest interrupt priority among processors that can receive the 326 // interrupt. 327 let redirection_hint: u8 = 1; 328 329 // Generate MSI message address 330 let low_addr: u32 = self.apic_address.0 as u32 331 | u32::from(destination_id) << 12 332 | u32::from(redirection_hint) << 3 333 | u32::from(destination_mode) << 2; 334 335 // Validate Trigger Mode value 336 let trigger_mode = trigger_mode(entry); 337 match trigger_mode { 338 x if (x == TriggerMode::Edge as u8) || (x == TriggerMode::Level as u8) => {} 339 _ => return Err(Error::InvalidTriggerMode), 340 } 341 342 // Validate Delivery Mode value 343 let delivery_mode = delivery_mode(entry); 344 match delivery_mode { 345 x if (x == DeliveryMode::Fixed as u8) 346 || (x == DeliveryMode::Lowest as u8) 347 || (x == DeliveryMode::Smi as u8) 348 || (x == DeliveryMode::RemoteRead as u8) 349 || (x == DeliveryMode::Nmi as u8) 350 || (x == DeliveryMode::Init as u8) 351 || (x == DeliveryMode::Startup as u8) 352 || (x == DeliveryMode::External as u8) => {} 353 _ => return Err(Error::InvalidDeliveryMode), 354 } 355 356 // Generate MSI message data 357 let data: u32 = u32::from(trigger_mode) << 15 358 | u32::from(remote_irr(entry)) << 14 359 | u32::from(delivery_mode) << 8 360 | u32::from(vector(entry)); 361 362 let config = MsiIrqSourceConfig { 363 high_addr: 0x0, 364 low_addr, 365 data, 366 devid: 0, 367 }; 368 369 self.interrupt_source_group 370 .update( 371 irq as InterruptIndex, 372 InterruptSourceConfig::MsiIrq(config), 373 interrupt_mask(entry) == 1, 374 ) 375 .map_err(Error::UpdateInterrupt)?; 376 377 Ok(()) 378 } 379 } 380 381 impl InterruptController for Ioapic { 382 // The ioapic must be informed about EOIs in order to deassert interrupts 383 // already sent. 384 fn end_of_interrupt(&mut self, vec: u8) { 385 for i in 0..NUM_IOAPIC_PINS { 386 let entry = &mut self.reg_entries[i]; 387 // Clear Remote IRR bit 388 if vector(*entry) == vec && trigger_mode(*entry) == 1 { 389 set_remote_irr(entry, 0); 390 } 391 } 392 } 393 394 // This should be called anytime an interrupt needs to be injected into the 395 // running guest. 396 fn service_irq(&mut self, irq: usize) -> Result<()> { 397 let entry = &mut self.reg_entries[irq]; 398 399 self.interrupt_source_group 400 .trigger(irq as InterruptIndex) 401 .map_err(Error::TriggerInterrupt)?; 402 debug!("Interrupt successfully delivered"); 403 404 // If trigger mode is level sensitive, set the Remote IRR bit. 405 // It will be cleared when the EOI is received. 406 if trigger_mode(*entry) == 1 { 407 set_remote_irr(entry, 1); 408 } 409 // Clear the Delivery Status bit 410 set_delivery_status(entry, 0); 411 412 Ok(()) 413 } 414 415 fn notifier(&self, irq: usize) -> Option<EventFd> { 416 self.interrupt_source_group.notifier(irq as InterruptIndex) 417 } 418 } 419 420 impl Snapshottable for Ioapic { 421 fn id(&self) -> String { 422 self.id.clone() 423 } 424 425 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 426 Snapshot::new_from_versioned_state(&self.id, &self.state()) 427 } 428 429 fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 430 self.set_state(&snapshot.to_versioned_state(&self.id)?) 431 .map_err(|e| { 432 MigratableError::Restore(anyhow!( 433 "Could not restore state for {}: {:?}", 434 self.id, 435 e 436 )) 437 }) 438 } 439 } 440 441 impl Pausable for Ioapic {} 442 impl Transportable for Ioapic {} 443 impl Migratable for Ioapic {} 444