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