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