xref: /aosp_15_r20/external/crosvm/x86_64/src/interrupts.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::result;
6 
7 use devices::IrqChipX86_64;
8 use remain::sorted;
9 use thiserror::Error;
10 
11 #[sorted]
12 #[derive(Error, Debug)]
13 pub enum Error {
14     #[error("GetLapic ioctl failed: {0}")]
15     GetLapic(base::Error),
16     #[error("SetLapic ioctl failed: {0}")]
17     SetLapic(base::Error),
18 }
19 
20 pub type Result<T> = result::Result<T, Error>;
21 
22 // Defines poached from apicdef.h kernel header.
23 
24 // Offset, in bytes, of LAPIC local vector table LINT0/LINT1 registers.
25 const APIC_LVT0_OFFSET: usize = 0x350;
26 const APIC_LVT1_OFFSET: usize = 0x360;
27 
28 // Register num of LINT0/LINT1 register.
29 const APIC_LVT0_REGISTER: usize = lapic_byte_offset_to_register(APIC_LVT0_OFFSET);
30 const APIC_LVT1_REGISTER: usize = lapic_byte_offset_to_register(APIC_LVT1_OFFSET);
31 
32 const APIC_MODE_NMI: u32 = 0x4;
33 const APIC_MODE_EXTINT: u32 = 0x7;
34 
35 // Converts a LAPIC register byte offset to a register number.
lapic_byte_offset_to_register(offset_bytes: usize) -> usize36 const fn lapic_byte_offset_to_register(offset_bytes: usize) -> usize {
37     // Registers are 16 byte aligned
38     offset_bytes / 16
39 }
40 
set_apic_delivery_mode(reg: u32, mode: u32) -> u3241 fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 {
42     ((reg) & !0x700) | ((mode) << 8)
43 }
44 
45 /// Configures LAPICs.  LAPIC0 is set for external interrupts, LAPIC1 is set for NMI.
46 ///
47 /// # Arguments
48 /// * `vcpu_id` - The number of the VCPU to configure.
49 /// * `irqchip` - The IrqChip for getting/setting LAPIC state.
set_lint(vcpu_id: usize, irqchip: &mut dyn IrqChipX86_64) -> Result<()>50 pub fn set_lint(vcpu_id: usize, irqchip: &mut dyn IrqChipX86_64) -> Result<()> {
51     let mut lapic = irqchip.get_lapic_state(vcpu_id).map_err(Error::GetLapic)?;
52 
53     for (reg, mode) in &[
54         (APIC_LVT0_REGISTER, APIC_MODE_EXTINT),
55         (APIC_LVT1_REGISTER, APIC_MODE_NMI),
56     ] {
57         lapic.regs[*reg] = set_apic_delivery_mode(lapic.regs[*reg], *mode);
58     }
59 
60     irqchip
61         .set_lapic_state(vcpu_id, &lapic)
62         .map_err(Error::SetLapic)
63 }
64