x86_64/
interrupts.rs

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
5use std::result;
6
7use devices::IrqChipX86_64;
8use remain::sorted;
9use thiserror::Error;
10
11#[sorted]
12#[derive(Error, Debug)]
13pub enum Error {
14    #[error("GetLapic ioctl failed: {0}")]
15    GetLapic(base::Error),
16    #[error("SetLapic ioctl failed: {0}")]
17    SetLapic(base::Error),
18}
19
20pub 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.
25const APIC_LVT0_OFFSET: usize = 0x350;
26const APIC_LVT1_OFFSET: usize = 0x360;
27
28// Register num of LINT0/LINT1 register.
29const APIC_LVT0_REGISTER: usize = lapic_byte_offset_to_register(APIC_LVT0_OFFSET);
30const APIC_LVT1_REGISTER: usize = lapic_byte_offset_to_register(APIC_LVT1_OFFSET);
31
32const APIC_MODE_NMI: u32 = 0x4;
33const APIC_MODE_EXTINT: u32 = 0x7;
34
35// Converts a LAPIC register byte offset to a register number.
36const fn lapic_byte_offset_to_register(offset_bytes: usize) -> usize {
37    // Registers are 16 byte aligned
38    offset_bytes / 16
39}
40
41fn 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.
50pub 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}