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