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