• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 use std::fmt::{self, Display};
6 use std::result;
7 
8 use devices::IrqChipX86_64;
9 
10 #[derive(Debug)]
11 pub enum Error {
12     GetLapic(base::Error),
13     SetLapic(base::Error),
14 }
15 pub type Result<T> = result::Result<T, Error>;
16 
17 impl std::error::Error for Error {}
18 
19 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result20     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21         use self::Error::*;
22 
23         match self {
24             GetLapic(e) => write!(f, "GetLapic ioctl failed: {}", e),
25             SetLapic(e) => write!(f, "SetLapic ioctl failed: {}", e),
26         }
27     }
28 }
29 
30 // Defines poached from apicdef.h kernel header.
31 
32 // Offset, in bytes, of LAPIC local vector table LINT0/LINT1 registers.
33 const APIC_LVT0_OFFSET: usize = 0x350;
34 const APIC_LVT1_OFFSET: usize = 0x360;
35 
36 // Register num of LINT0/LINT1 register.
37 const APIC_LVT0_REGISTER: usize = lapic_byte_offset_to_register(APIC_LVT0_OFFSET);
38 const APIC_LVT1_REGISTER: usize = lapic_byte_offset_to_register(APIC_LVT1_OFFSET);
39 
40 const APIC_MODE_NMI: u32 = 0x4;
41 const APIC_MODE_EXTINT: u32 = 0x7;
42 
43 // Converts a LAPIC register byte offset to a register number.
lapic_byte_offset_to_register(offset_bytes: usize) -> usize44 const fn lapic_byte_offset_to_register(offset_bytes: usize) -> usize {
45     // Registers are 16 byte aligned
46     offset_bytes / 16
47 }
48 
set_apic_delivery_mode(reg: u32, mode: u32) -> u3249 fn set_apic_delivery_mode(reg: u32, mode: u32) -> u32 {
50     ((reg) & !0x700) | ((mode) << 8)
51 }
52 
53 /// Configures LAPICs.  LAPIC0 is set for external interrupts, LAPIC1 is set for NMI.
54 ///
55 /// # Arguments
56 /// * `vcpu_id` - The number of the VCPU to configure.
57 /// * `irqchip` - The IrqChip for getting/setting LAPIC state.
set_lint(vcpu_id: usize, irqchip: &mut dyn IrqChipX86_64) -> Result<()>58 pub fn set_lint(vcpu_id: usize, irqchip: &mut dyn IrqChipX86_64) -> Result<()> {
59     let mut lapic = irqchip.get_lapic_state(vcpu_id).map_err(Error::GetLapic)?;
60 
61     for (reg, mode) in &[
62         (APIC_LVT0_REGISTER, APIC_MODE_EXTINT),
63         (APIC_LVT1_REGISTER, APIC_MODE_NMI),
64     ] {
65         lapic.regs[*reg] = set_apic_delivery_mode(lapic.regs[*reg], *mode);
66     }
67 
68     irqchip
69         .set_lapic_state(vcpu_id, &lapic)
70         .map_err(Error::SetLapic)
71 }
72