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)?; 241 } 242 } 243 } 244 245 Ok(ioapic) 246 } 247 248 fn ioapic_write(&mut self, val: u32) { 249 debug!("IOAPIC_W reg 0x{:x}, val 0x{:x}", self.reg_sel, val); 250 251 match self.reg_sel as u8 { 252 IOAPIC_REG_VERSION => { 253 if val == 0 { 254 // Windows writes zero here (see #1791) 255 } else { 256 error!( 257 "IOAPIC: invalid write to version register (0x{:x}): 0x{:x}", 258 self.reg_sel, val 259 ); 260 } 261 } 262 IOAPIC_REG_ID => self.id_reg = (val >> 24) & 0xf, 263 IOWIN_OFF..=REG_MAX_OFFSET => { 264 let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8); 265 if index > NUM_IOAPIC_PINS { 266 warn!("IOAPIC index out of range: {}", index); 267 return; 268 } 269 if is_high_bits { 270 self.reg_entries[index] &= 0xffff_ffff; 271 self.reg_entries[index] |= u64::from(val) << 32; 272 } else { 273 // Ensure not to override read-only bits: 274 // - Delivery Status (bit 12) 275 // - Remote IRR (bit 14) 276 self.reg_entries[index] &= 0xffff_ffff_0000_5000; 277 self.reg_entries[index] |= u64::from(val) & 0xffff_afff; 278 } 279 // The entry must be updated through the interrupt source 280 // group. 281 if let Err(e) = self.update_entry(index) { 282 error!("Failed updating IOAPIC entry: {:?}", e); 283 } 284 // Store the information this IRQ is now being used. 285 self.used_entries[index] = true; 286 } 287 _ => error!( 288 "IOAPIC: invalid write to register offset 0x{:x}", 289 self.reg_sel 290 ), 291 } 292 } 293 294 fn ioapic_read(&self) -> u32 { 295 debug!("IOAPIC_R reg 0x{:x}", self.reg_sel); 296 297 match self.reg_sel as u8 { 298 IOAPIC_REG_VERSION => IOAPIC_VERSION_ID, 299 IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => (self.id_reg & 0xf) << 24, 300 IOWIN_OFF..=REG_MAX_OFFSET => { 301 let (index, is_high_bits) = decode_irq_from_selector(self.reg_sel as u8); 302 if index > NUM_IOAPIC_PINS { 303 warn!("IOAPIC index out of range: {}", index); 304 return 0; 305 } 306 if is_high_bits { 307 (self.reg_entries[index] >> 32) as u32 308 } else { 309 (self.reg_entries[index] & 0xffff_ffff) as u32 310 } 311 } 312 _ => { 313 error!( 314 "IOAPIC: invalid read from register offset 0x{:x}", 315 self.reg_sel 316 ); 317 0 318 } 319 } 320 } 321 322 fn state(&self) -> IoapicState { 323 IoapicState { 324 id_reg: self.id_reg, 325 reg_sel: self.reg_sel, 326 reg_entries: self.reg_entries, 327 used_entries: self.used_entries, 328 apic_address: self.apic_address.0, 329 } 330 } 331 332 fn update_entry(&self, irq: usize) -> Result<()> { 333 let entry = self.reg_entries[irq]; 334 335 // Validate Destination Mode value, and retrieve Destination ID 336 let destination_mode = destination_mode(entry); 337 let destination_id = destination_field(entry); 338 339 // When this bit is set, the message is directed to the processor with 340 // the lowest interrupt priority among processors that can receive the 341 // interrupt. 342 let redirection_hint: u8 = 1; 343 344 // Generate MSI message address 345 let low_addr: u32 = self.apic_address.0 as u32 346 | u32::from(destination_id) << 12 347 | u32::from(redirection_hint) << 3 348 | u32::from(destination_mode) << 2; 349 350 // Validate Trigger Mode value 351 let trigger_mode = trigger_mode(entry); 352 match trigger_mode { 353 x if (x == TriggerMode::Edge as u8) || (x == TriggerMode::Level as u8) => {} 354 _ => return Err(Error::InvalidTriggerMode), 355 } 356 357 // Validate Delivery Mode value 358 let delivery_mode = delivery_mode(entry); 359 match delivery_mode { 360 x if (x == DeliveryMode::Fixed as u8) 361 || (x == DeliveryMode::Lowest as u8) 362 || (x == DeliveryMode::Smi as u8) 363 || (x == DeliveryMode::RemoteRead as u8) 364 || (x == DeliveryMode::Nmi as u8) 365 || (x == DeliveryMode::Init as u8) 366 || (x == DeliveryMode::Startup as u8) 367 || (x == DeliveryMode::External as u8) => {} 368 _ => return Err(Error::InvalidDeliveryMode), 369 } 370 371 // Generate MSI message data 372 let data: u32 = u32::from(trigger_mode) << 15 373 | u32::from(remote_irr(entry)) << 14 374 | u32::from(delivery_mode) << 8 375 | u32::from(vector(entry)); 376 377 let config = MsiIrqSourceConfig { 378 high_addr: 0x0, 379 low_addr, 380 data, 381 devid: 0, 382 }; 383 384 self.interrupt_source_group 385 .update( 386 irq as InterruptIndex, 387 InterruptSourceConfig::MsiIrq(config), 388 interrupt_mask(entry) == 1, 389 ) 390 .map_err(Error::UpdateInterrupt)?; 391 392 Ok(()) 393 } 394 } 395 396 impl InterruptController for Ioapic { 397 // The ioapic must be informed about EOIs in order to deassert interrupts 398 // already sent. 399 fn end_of_interrupt(&mut self, vec: u8) { 400 for i in 0..NUM_IOAPIC_PINS { 401 let entry = &mut self.reg_entries[i]; 402 // Clear Remote IRR bit 403 if vector(*entry) == vec && trigger_mode(*entry) == 1 { 404 set_remote_irr(entry, 0); 405 } 406 } 407 } 408 409 // This should be called anytime an interrupt needs to be injected into the 410 // running guest. 411 fn service_irq(&mut self, irq: usize) -> Result<()> { 412 let entry = &mut self.reg_entries[irq]; 413 414 self.interrupt_source_group 415 .trigger(irq as InterruptIndex) 416 .map_err(Error::TriggerInterrupt)?; 417 debug!("Interrupt successfully delivered"); 418 419 // If trigger mode is level sensitive, set the Remote IRR bit. 420 // It will be cleared when the EOI is received. 421 if trigger_mode(*entry) == 1 { 422 set_remote_irr(entry, 1); 423 } 424 // Clear the Delivery Status bit 425 set_delivery_status(entry, 0); 426 427 Ok(()) 428 } 429 430 fn notifier(&self, irq: usize) -> Option<EventFd> { 431 self.interrupt_source_group.notifier(irq as InterruptIndex) 432 } 433 } 434 435 impl Snapshottable for Ioapic { 436 fn id(&self) -> String { 437 self.id.clone() 438 } 439 440 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 441 Snapshot::new_from_versioned_state(&self.id, &self.state()) 442 } 443 } 444 445 impl Pausable for Ioapic {} 446 impl Transportable for Ioapic {} 447 impl Migratable for Ioapic {} 448