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
vector(entry: RedirectionTableEntry) -> u848 fn vector(entry: RedirectionTableEntry) -> u8 {
49 (entry & 0xffu64) as u8
50 }
delivery_mode(entry: RedirectionTableEntry) -> u851 fn delivery_mode(entry: RedirectionTableEntry) -> u8 {
52 ((entry >> 8) & 0x7u64) as u8
53 }
destination_mode(entry: RedirectionTableEntry) -> u854 fn destination_mode(entry: RedirectionTableEntry) -> u8 {
55 ((entry >> 11) & 0x1u64) as u8
56 }
remote_irr(entry: RedirectionTableEntry) -> u857 fn remote_irr(entry: RedirectionTableEntry) -> u8 {
58 ((entry >> 14) & 0x1u64) as u8
59 }
trigger_mode(entry: RedirectionTableEntry) -> u860 fn trigger_mode(entry: RedirectionTableEntry) -> u8 {
61 ((entry >> 15) & 0x1u64) as u8
62 }
interrupt_mask(entry: RedirectionTableEntry) -> u863 fn interrupt_mask(entry: RedirectionTableEntry) -> u8 {
64 ((entry >> 16) & 0x1u64) as u8
65 }
destination_field(entry: RedirectionTableEntry) -> u866 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 }
set_delivery_status(entry: &mut RedirectionTableEntry, val: u8)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 }
set_remote_irr(entry: &mut RedirectionTableEntry, val: u8)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.
decode_irq_from_selector(selector: u8) -> (usize, bool)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 {
read(&mut self, _base: u64, offset: u64, data: &mut [u8])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
write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>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 {
new( id: String, apic_address: GuestAddress, interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>, state: Option<IoapicState>, ) -> Result<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
ioapic_write(&mut self, val: u32)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
ioapic_read(&self) -> u32297 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
state(&self) -> IoapicState325 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
update_entry(&self, irq: usize, set_gsi: bool) -> Result<()>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.
end_of_interrupt(&mut self, vec: u8)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.
service_irq(&mut self, irq: usize) -> Result<()>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
notifier(&self, irq: usize) -> Option<EventFd>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 {
id(&self) -> String440 fn id(&self) -> String {
441 self.id.clone()
442 }
443
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>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