1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 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 // Implementation of an xAPIC Local Advanced Programmable Interrupt Controller (LAPIC, aka APIC). 6*bb4ee6a4SAndroid Build Coastguard Worker // See Intel Software Developer's Manual, Volume 3A, chapter 10 for a specification. 7*bb4ee6a4SAndroid Build Coastguard Worker // 8*bb4ee6a4SAndroid Build Coastguard Worker // Some features from the spec aren't supported: 9*bb4ee6a4SAndroid Build Coastguard Worker // * setting TPR with cr8 register 10*bb4ee6a4SAndroid Build Coastguard Worker // * changing MMIO base address 11*bb4ee6a4SAndroid Build Coastguard Worker // * enabling/disabling the APIC with IA32_APIC_BASE MSR 12*bb4ee6a4SAndroid Build Coastguard Worker // * TSC-deadline timer mode 13*bb4ee6a4SAndroid Build Coastguard Worker // * cluster-mode logical addressing 14*bb4ee6a4SAndroid Build Coastguard Worker // * external interrupts -- these are handled by querying `Pic` separately in 15*bb4ee6a4SAndroid Build Coastguard Worker // `UserspaceIrqChip::inject_interrupts` 16*bb4ee6a4SAndroid Build Coastguard Worker 17*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryFrom; 18*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto; 19*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration; 20*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant; 21*bb4ee6a4SAndroid Build Coastguard Worker 22*bb4ee6a4SAndroid Build Coastguard Worker use base::error; 23*bb4ee6a4SAndroid Build Coastguard Worker use base::warn; 24*bb4ee6a4SAndroid Build Coastguard Worker use base::TimerTrait; 25*bb4ee6a4SAndroid Build Coastguard Worker use bit_field::*; 26*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::DeliveryMode; 27*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::DeliveryStatus; 28*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::DestinationMode; 29*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::LapicState; 30*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Level; 31*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MPState; 32*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MsiAddressMessage; 33*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MsiDataMessage; 34*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::TriggerMode; 35*bb4ee6a4SAndroid Build Coastguard Worker 36*bb4ee6a4SAndroid Build Coastguard Worker pub type Vector = u8; 37*bb4ee6a4SAndroid Build Coastguard Worker 38*bb4ee6a4SAndroid Build Coastguard Worker /// Address of the start of APIC MMIO region. 39*bb4ee6a4SAndroid Build Coastguard Worker pub const APIC_BASE_ADDRESS: u64 = 0xFEE00000; 40*bb4ee6a4SAndroid Build Coastguard Worker /// Length in bytes of APIC MMIO region. 41*bb4ee6a4SAndroid Build Coastguard Worker pub const APIC_MEM_LENGTH_BYTES: u64 = 0x1000; 42*bb4ee6a4SAndroid Build Coastguard Worker 43*bb4ee6a4SAndroid Build Coastguard Worker // We try to set the APIC timer frequency to the TSC frequency, but if TSC frequency can't be 44*bb4ee6a4SAndroid Build Coastguard Worker // determined, we use this cycle length as a fallback. 45*bb4ee6a4SAndroid Build Coastguard Worker const CYCLE_LENGTH_FALLBACK: Duration = Duration::from_nanos(10); 46*bb4ee6a4SAndroid Build Coastguard Worker // Size (alignment) of each register is 16 bytes. Only the first 4 bytes are actually used. 47*bb4ee6a4SAndroid Build Coastguard Worker const REG_ALIGN_BYTES: usize = 16; 48*bb4ee6a4SAndroid Build Coastguard Worker // APIC ID of the processor that starts executing instructions at power on (BSP). 49*bb4ee6a4SAndroid Build Coastguard Worker const BOOTSTRAP_PROCESSOR: u8 = 0; 50*bb4ee6a4SAndroid Build Coastguard Worker // 14 is the version for Xeon processors 51*bb4ee6a4SAndroid Build Coastguard Worker const VERSION: u8 = 0x14; 52*bb4ee6a4SAndroid Build Coastguard Worker // There are 6 local vector table entries in this version, so the max entry is offset 5. 53*bb4ee6a4SAndroid Build Coastguard Worker const MAX_LVT: u8 = 5; 54*bb4ee6a4SAndroid Build Coastguard Worker // Register value to mask an interrupt in the local vector table. 55*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_VECTOR_MASKED: u32 = 1 << 16; 56*bb4ee6a4SAndroid Build Coastguard Worker // Flat-model logical destinations. 57*bb4ee6a4SAndroid Build Coastguard Worker const DESTINATION_FORMAT_FLAT: u8 = 0xF; 58*bb4ee6a4SAndroid Build Coastguard Worker // Cluster-model logical destinations. 59*bb4ee6a4SAndroid Build Coastguard Worker const DESTINATION_FORMAT_CLUSTER: u8 = 0x0; 60*bb4ee6a4SAndroid Build Coastguard Worker // Physical destination address that goes to all CPUs. 61*bb4ee6a4SAndroid Build Coastguard Worker const PHYSICAL_BROADCAST_ADDRESS: u8 = 0xFF; 62*bb4ee6a4SAndroid Build Coastguard Worker // Bitmask for the APIC software enable bit in the Spurious Int register. 63*bb4ee6a4SAndroid Build Coastguard Worker const SOFTWARE_ENABLE: u32 = 1 << 8; 64*bb4ee6a4SAndroid Build Coastguard Worker // Bitmask for timer mode bits in the Local Timer register. 65*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_MODE_MASK: u32 = 3 << 17; 66*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_MODE_ONE_SHOT: u32 = 0 << 17; 67*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_MODE_PERIODIC: u32 = 1 << 17; 68*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_MODE_TSC_DEADLINE: u32 = 2 << 17; 69*bb4ee6a4SAndroid Build Coastguard Worker // Table for mapping Divide Configuration Register values to timer divisors. The APIC's timer 70*bb4ee6a4SAndroid Build Coastguard Worker // frequency is the base frequency divided by the value from this table. 71*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_DIVIDE_TABLE: [u32; 16] = [ 72*bb4ee6a4SAndroid Build Coastguard Worker 2, 4, 8, 16, // 73*bb4ee6a4SAndroid Build Coastguard Worker 1, 1, 1, 1, // Values with bit 2 are reserved and shouldn't be set 74*bb4ee6a4SAndroid Build Coastguard Worker 32, 64, 128, 1, // 75*bb4ee6a4SAndroid Build Coastguard Worker 1, 1, 1, 1, // Values with bit 2 are reserved and shouldn't be set 76*bb4ee6a4SAndroid Build Coastguard Worker ]; 77*bb4ee6a4SAndroid Build Coastguard Worker const ZERO_DURATION: Duration = Duration::from_nanos(0); 78*bb4ee6a4SAndroid Build Coastguard Worker 79*bb4ee6a4SAndroid Build Coastguard Worker pub struct Apic { 80*bb4ee6a4SAndroid Build Coastguard Worker // Local APIC ID. 81*bb4ee6a4SAndroid Build Coastguard Worker id: u8, 82*bb4ee6a4SAndroid Build Coastguard Worker /// Base duration for the APIC timer. A timer set with initial count = 1 and timer frequency 83*bb4ee6a4SAndroid Build Coastguard Worker /// divide = 1 runs for this long. 84*bb4ee6a4SAndroid Build Coastguard Worker cycle_length: Duration, 85*bb4ee6a4SAndroid Build Coastguard Worker // Register state bytes. Each register is 16-byte aligned, but only its first 4 bytes are 86*bb4ee6a4SAndroid Build Coastguard Worker // used. The register MMIO space is 4 KiB, but only the first 1 KiB (64 registers * 16 87*bb4ee6a4SAndroid Build Coastguard Worker // bytes) is used. 88*bb4ee6a4SAndroid Build Coastguard Worker regs: [u8; APIC_MEM_LENGTH_BYTES as usize], 89*bb4ee6a4SAndroid Build Coastguard Worker // Multiprocessing initialization state: running, waiting for SIPI, etc. 90*bb4ee6a4SAndroid Build Coastguard Worker mp_state: MPState, 91*bb4ee6a4SAndroid Build Coastguard Worker // Timer for one-shot and periodic timer interrupts. 92*bb4ee6a4SAndroid Build Coastguard Worker timer: Box<dyn TimerTrait>, 93*bb4ee6a4SAndroid Build Coastguard Worker // How long the timer was set for. If the timer is not set (not running), it's None. For 94*bb4ee6a4SAndroid Build Coastguard Worker // one-shot timers, it's the duration from start until expiration. For periodic timers, it's 95*bb4ee6a4SAndroid Build Coastguard Worker //the timer interval. 96*bb4ee6a4SAndroid Build Coastguard Worker timer_length: Option<Duration>, 97*bb4ee6a4SAndroid Build Coastguard Worker // When the timer started or last ticked. For one-shot timers, this is the Instant when the 98*bb4ee6a4SAndroid Build Coastguard Worker // timer started. For periodic timers, it's the Instant when it started or last expired. 99*bb4ee6a4SAndroid Build Coastguard Worker last_tick: Instant, 100*bb4ee6a4SAndroid Build Coastguard Worker // Pending startup interrupt vector. There can only be one pending startup interrupt at a 101*bb4ee6a4SAndroid Build Coastguard Worker // time. 102*bb4ee6a4SAndroid Build Coastguard Worker sipi: Option<Vector>, 103*bb4ee6a4SAndroid Build Coastguard Worker // True if there's a pending INIT interrupt to send to the CPU. 104*bb4ee6a4SAndroid Build Coastguard Worker init: bool, 105*bb4ee6a4SAndroid Build Coastguard Worker // The number of pending non-maskable interrupts to be injected into the CPU. The architecture 106*bb4ee6a4SAndroid Build Coastguard Worker // specifies that multiple NMIs can be sent concurrently and will be processed in order. 107*bb4ee6a4SAndroid Build Coastguard Worker // Unlike fixed interrupts there's no architecturally defined place where the NMIs are 108*bb4ee6a4SAndroid Build Coastguard Worker // queued or stored, we need to store them separately. 109*bb4ee6a4SAndroid Build Coastguard Worker nmis: u32, 110*bb4ee6a4SAndroid Build Coastguard Worker } 111*bb4ee6a4SAndroid Build Coastguard Worker 112*bb4ee6a4SAndroid Build Coastguard Worker impl Apic { 113*bb4ee6a4SAndroid Build Coastguard Worker /// Constructs a new APIC with local APIC ID `id`. new(id: u8, timer: Box<dyn TimerTrait>) -> Self114*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(id: u8, timer: Box<dyn TimerTrait>) -> Self { 115*bb4ee6a4SAndroid Build Coastguard Worker let cycle_length = Duration::from_nanos(1_000_000_000 / Self::frequency() as u64); 116*bb4ee6a4SAndroid Build Coastguard Worker let mp_state = if id == BOOTSTRAP_PROCESSOR { 117*bb4ee6a4SAndroid Build Coastguard Worker MPState::Runnable 118*bb4ee6a4SAndroid Build Coastguard Worker } else { 119*bb4ee6a4SAndroid Build Coastguard Worker MPState::Uninitialized 120*bb4ee6a4SAndroid Build Coastguard Worker }; 121*bb4ee6a4SAndroid Build Coastguard Worker let mut apic = Apic { 122*bb4ee6a4SAndroid Build Coastguard Worker id, 123*bb4ee6a4SAndroid Build Coastguard Worker cycle_length, 124*bb4ee6a4SAndroid Build Coastguard Worker regs: [0; APIC_MEM_LENGTH_BYTES as usize], 125*bb4ee6a4SAndroid Build Coastguard Worker mp_state, 126*bb4ee6a4SAndroid Build Coastguard Worker timer, 127*bb4ee6a4SAndroid Build Coastguard Worker timer_length: None, 128*bb4ee6a4SAndroid Build Coastguard Worker last_tick: Instant::now(), 129*bb4ee6a4SAndroid Build Coastguard Worker sipi: None, 130*bb4ee6a4SAndroid Build Coastguard Worker init: false, 131*bb4ee6a4SAndroid Build Coastguard Worker nmis: 0, 132*bb4ee6a4SAndroid Build Coastguard Worker }; 133*bb4ee6a4SAndroid Build Coastguard Worker apic.load_reset_state(); 134*bb4ee6a4SAndroid Build Coastguard Worker apic 135*bb4ee6a4SAndroid Build Coastguard Worker } 136*bb4ee6a4SAndroid Build Coastguard Worker 137*bb4ee6a4SAndroid Build Coastguard Worker /// Get the Apic frequency in Hz frequency() -> u32138*bb4ee6a4SAndroid Build Coastguard Worker pub fn frequency() -> u32 { 139*bb4ee6a4SAndroid Build Coastguard Worker // Our Apic implementation will try to use the host's bus frequency if it 140*bb4ee6a4SAndroid Build Coastguard Worker // can be determined from cpuid, otherwise it uses 100MHz (cycle length of 10 nanos) 141*bb4ee6a4SAndroid Build Coastguard Worker match crate::tsc::bus_freq_hz(std::arch::x86_64::__cpuid_count) { 142*bb4ee6a4SAndroid Build Coastguard Worker Some(hz) => hz, 143*bb4ee6a4SAndroid Build Coastguard Worker None => (1_000_000_000u128 / CYCLE_LENGTH_FALLBACK.as_nanos()) as u32, 144*bb4ee6a4SAndroid Build Coastguard Worker } 145*bb4ee6a4SAndroid Build Coastguard Worker } 146*bb4ee6a4SAndroid Build Coastguard Worker 147*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the local APIC ID. id(&self) -> u8148*bb4ee6a4SAndroid Build Coastguard Worker pub fn id(&self) -> u8 { 149*bb4ee6a4SAndroid Build Coastguard Worker self.id 150*bb4ee6a4SAndroid Build Coastguard Worker } 151*bb4ee6a4SAndroid Build Coastguard Worker 152*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the base duration for the APIC timer. A timer set with initial count = 1 and timer 153*bb4ee6a4SAndroid Build Coastguard Worker /// frequency divide = 1 runs for this long. get_cycle_length(&self) -> Duration154*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_cycle_length(&self) -> Duration { 155*bb4ee6a4SAndroid Build Coastguard Worker self.cycle_length 156*bb4ee6a4SAndroid Build Coastguard Worker } 157*bb4ee6a4SAndroid Build Coastguard Worker 158*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the state of the APIC registers. get_state(&self) -> LapicState159*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_state(&self) -> LapicState { 160*bb4ee6a4SAndroid Build Coastguard Worker let mut state = LapicState { regs: [0; 64] }; 161*bb4ee6a4SAndroid Build Coastguard Worker for reg in 0..state.regs.len() { 162*bb4ee6a4SAndroid Build Coastguard Worker state.regs[reg] = self.get_reg(reg * REG_ALIGN_BYTES); 163*bb4ee6a4SAndroid Build Coastguard Worker } 164*bb4ee6a4SAndroid Build Coastguard Worker state 165*bb4ee6a4SAndroid Build Coastguard Worker } 166*bb4ee6a4SAndroid Build Coastguard Worker 167*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the state of the APIC registers. set_state(&mut self, state: &LapicState)168*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_state(&mut self, state: &LapicState) { 169*bb4ee6a4SAndroid Build Coastguard Worker for (reg, val) in state.regs.iter().enumerate() { 170*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(reg * REG_ALIGN_BYTES, *val); 171*bb4ee6a4SAndroid Build Coastguard Worker } 172*bb4ee6a4SAndroid Build Coastguard Worker 173*bb4ee6a4SAndroid Build Coastguard Worker // This has the same timer semantics as KVM. Timers that are in-progress during get_state 174*bb4ee6a4SAndroid Build Coastguard Worker // are ignored and during set_state timers are restarted regardless of how much of the timer 175*bb4ee6a4SAndroid Build Coastguard Worker // has already expired. 176*bb4ee6a4SAndroid Build Coastguard Worker self.start_timer(); 177*bb4ee6a4SAndroid Build Coastguard Worker } 178*bb4ee6a4SAndroid Build Coastguard Worker 179*bb4ee6a4SAndroid Build Coastguard Worker /// Gets the multi-processing state. get_mp_state(&self) -> MPState180*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_mp_state(&self) -> MPState { 181*bb4ee6a4SAndroid Build Coastguard Worker self.mp_state 182*bb4ee6a4SAndroid Build Coastguard Worker } 183*bb4ee6a4SAndroid Build Coastguard Worker 184*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the multi-processing state. set_mp_state(&mut self, state: &MPState)185*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_mp_state(&mut self, state: &MPState) { 186*bb4ee6a4SAndroid Build Coastguard Worker self.mp_state = *state; 187*bb4ee6a4SAndroid Build Coastguard Worker } 188*bb4ee6a4SAndroid Build Coastguard Worker 189*bb4ee6a4SAndroid Build Coastguard Worker /// Checks that `offset` is 16-byte aligned and `data` is 4 bytes. valid_mmio(offset: u64, data: &[u8]) -> bool190*bb4ee6a4SAndroid Build Coastguard Worker fn valid_mmio(offset: u64, data: &[u8]) -> bool { 191*bb4ee6a4SAndroid Build Coastguard Worker if offset.trailing_zeros() >= 4 && data.len() == 4 { 192*bb4ee6a4SAndroid Build Coastguard Worker true 193*bb4ee6a4SAndroid Build Coastguard Worker } else { 194*bb4ee6a4SAndroid Build Coastguard Worker error!( 195*bb4ee6a4SAndroid Build Coastguard Worker "Invalid offset {} or size {} for apic mmio", 196*bb4ee6a4SAndroid Build Coastguard Worker offset, 197*bb4ee6a4SAndroid Build Coastguard Worker data.len() 198*bb4ee6a4SAndroid Build Coastguard Worker ); 199*bb4ee6a4SAndroid Build Coastguard Worker false 200*bb4ee6a4SAndroid Build Coastguard Worker } 201*bb4ee6a4SAndroid Build Coastguard Worker } 202*bb4ee6a4SAndroid Build Coastguard Worker 203*bb4ee6a4SAndroid Build Coastguard Worker /// Handles an MMIO read forwarded from the IRQ chip. Reads data from the APIC's register at 204*bb4ee6a4SAndroid Build Coastguard Worker /// `offset` into `data`. read(&self, offset: u64, data: &mut [u8])205*bb4ee6a4SAndroid Build Coastguard Worker pub fn read(&self, offset: u64, data: &mut [u8]) { 206*bb4ee6a4SAndroid Build Coastguard Worker if !Self::valid_mmio(offset, data) { 207*bb4ee6a4SAndroid Build Coastguard Worker return; 208*bb4ee6a4SAndroid Build Coastguard Worker } 209*bb4ee6a4SAndroid Build Coastguard Worker let offset = offset as usize; 210*bb4ee6a4SAndroid Build Coastguard Worker let val = match offset { 211*bb4ee6a4SAndroid Build Coastguard Worker Reg::PPR => self.get_processor_priority() as u32, 212*bb4ee6a4SAndroid Build Coastguard Worker Reg::TIMER_CURRENT_COUNT => { 213*bb4ee6a4SAndroid Build Coastguard Worker let count_remaining = self.next_timer_expiration().as_nanos() 214*bb4ee6a4SAndroid Build Coastguard Worker / self.cycle_length.as_nanos() 215*bb4ee6a4SAndroid Build Coastguard Worker / self.get_timer_divide_control() as u128; 216*bb4ee6a4SAndroid Build Coastguard Worker count_remaining.try_into().unwrap_or_else(|_| { 217*bb4ee6a4SAndroid Build Coastguard Worker warn!("APIC time remaining overflow"); 218*bb4ee6a4SAndroid Build Coastguard Worker u32::MAX 219*bb4ee6a4SAndroid Build Coastguard Worker }) 220*bb4ee6a4SAndroid Build Coastguard Worker } 221*bb4ee6a4SAndroid Build Coastguard Worker _ => self.get_reg(offset), 222*bb4ee6a4SAndroid Build Coastguard Worker }; 223*bb4ee6a4SAndroid Build Coastguard Worker data.copy_from_slice(&val.to_le_bytes()); 224*bb4ee6a4SAndroid Build Coastguard Worker } 225*bb4ee6a4SAndroid Build Coastguard Worker 226*bb4ee6a4SAndroid Build Coastguard Worker /// Handles an MMIO write forwarded from the IRQ chip. Writes `data` into the APIC's register 227*bb4ee6a4SAndroid Build Coastguard Worker /// at `offset`, optionally returning a command back to the IRQ chip. write(&mut self, offset: u64, data: &[u8]) -> Option<ApicBusMsg>228*bb4ee6a4SAndroid Build Coastguard Worker pub fn write(&mut self, offset: u64, data: &[u8]) -> Option<ApicBusMsg> { 229*bb4ee6a4SAndroid Build Coastguard Worker if !Self::valid_mmio(offset, data) { 230*bb4ee6a4SAndroid Build Coastguard Worker return None; 231*bb4ee6a4SAndroid Build Coastguard Worker } 232*bb4ee6a4SAndroid Build Coastguard Worker let offset = offset as usize; 233*bb4ee6a4SAndroid Build Coastguard Worker let data = u32::from_le_bytes(data.try_into().unwrap()); 234*bb4ee6a4SAndroid Build Coastguard Worker let mut msg: Option<ApicBusMsg> = None; 235*bb4ee6a4SAndroid Build Coastguard Worker match offset { 236*bb4ee6a4SAndroid Build Coastguard Worker Reg::ID => {} 237*bb4ee6a4SAndroid Build Coastguard Worker Reg::TPR => self.set_reg(Reg::TPR, data & 0xFF), // Top 24 bits are reserved. 238*bb4ee6a4SAndroid Build Coastguard Worker Reg::EOI => { 239*bb4ee6a4SAndroid Build Coastguard Worker // TODO(srichman): Implement eoi broadcast suppression. 240*bb4ee6a4SAndroid Build Coastguard Worker if let Some(vector) = self.highest_bit_in_vector(VectorReg::Isr) { 241*bb4ee6a4SAndroid Build Coastguard Worker self.clear_vector_bit(VectorReg::Isr, vector); 242*bb4ee6a4SAndroid Build Coastguard Worker msg = Some(ApicBusMsg::Eoi(vector)); 243*bb4ee6a4SAndroid Build Coastguard Worker // The next call to UserspaceIrqChip::inject_interrupts() at end of the vcpu run 244*bb4ee6a4SAndroid Build Coastguard Worker // loop will finish the EOI steps by injecting the highest vector in IRR, if 245*bb4ee6a4SAndroid Build Coastguard Worker // any. 246*bb4ee6a4SAndroid Build Coastguard Worker } 247*bb4ee6a4SAndroid Build Coastguard Worker } 248*bb4ee6a4SAndroid Build Coastguard Worker Reg::INTERRUPT_COMMAND_LO => { 249*bb4ee6a4SAndroid Build Coastguard Worker // When handling writes to the ICR, we clear the pending bit. 250*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::INTERRUPT_COMMAND_LO, data & !(1 << 12)); 251*bb4ee6a4SAndroid Build Coastguard Worker let interrupt = self.decode_icr(); 252*bb4ee6a4SAndroid Build Coastguard Worker msg = Some(ApicBusMsg::Ipi(interrupt)); 253*bb4ee6a4SAndroid Build Coastguard Worker } 254*bb4ee6a4SAndroid Build Coastguard Worker 255*bb4ee6a4SAndroid Build Coastguard Worker // TODO(srichman): Many of these have reserved bits which are not supposed to be set. 256*bb4ee6a4SAndroid Build Coastguard Worker // Currently we allow a guest to set them. 257*bb4ee6a4SAndroid Build Coastguard Worker // TODO(srichman): Handle software disable closer to spec: set LVT mask bits and don't 258*bb4ee6a4SAndroid Build Coastguard Worker // accept new irqs. 259*bb4ee6a4SAndroid Build Coastguard Worker Reg::TIMER_DIVIDE_CONTROL 260*bb4ee6a4SAndroid Build Coastguard Worker | Reg::LOCAL_CMCI 261*bb4ee6a4SAndroid Build Coastguard Worker | Reg::INTERRUPT_COMMAND_HI 262*bb4ee6a4SAndroid Build Coastguard Worker | Reg::SPURIOUS_INT 263*bb4ee6a4SAndroid Build Coastguard Worker | Reg::LOGICAL_DESTINATION 264*bb4ee6a4SAndroid Build Coastguard Worker | Reg::DESTINATION_FORMAT => self.set_reg(offset, data), 265*bb4ee6a4SAndroid Build Coastguard Worker 266*bb4ee6a4SAndroid Build Coastguard Worker Reg::LOCAL_INT_0 267*bb4ee6a4SAndroid Build Coastguard Worker | Reg::LOCAL_INT_1 268*bb4ee6a4SAndroid Build Coastguard Worker | Reg::LOCAL_THERMAL 269*bb4ee6a4SAndroid Build Coastguard Worker | Reg::LOCAL_PERF 270*bb4ee6a4SAndroid Build Coastguard Worker | Reg::LOCAL_ERROR => { 271*bb4ee6a4SAndroid Build Coastguard Worker if self.enabled() { 272*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(offset, data); 273*bb4ee6a4SAndroid Build Coastguard Worker } else { 274*bb4ee6a4SAndroid Build Coastguard Worker // If the APIC is software disabled then the Masked bit can not be unset. 275*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(offset, data | LOCAL_VECTOR_MASKED); 276*bb4ee6a4SAndroid Build Coastguard Worker } 277*bb4ee6a4SAndroid Build Coastguard Worker } 278*bb4ee6a4SAndroid Build Coastguard Worker 279*bb4ee6a4SAndroid Build Coastguard Worker Reg::TIMER_INITIAL_COUNT => { 280*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::TIMER_INITIAL_COUNT, data); 281*bb4ee6a4SAndroid Build Coastguard Worker self.start_timer(); 282*bb4ee6a4SAndroid Build Coastguard Worker } 283*bb4ee6a4SAndroid Build Coastguard Worker Reg::LOCAL_TIMER => { 284*bb4ee6a4SAndroid Build Coastguard Worker let old_mode = self.get_reg(Reg::LOCAL_TIMER) & TIMER_MODE_MASK; 285*bb4ee6a4SAndroid Build Coastguard Worker let new_mode = data & TIMER_MODE_MASK; 286*bb4ee6a4SAndroid Build Coastguard Worker if old_mode != new_mode { 287*bb4ee6a4SAndroid Build Coastguard Worker self.clear_timer(); 288*bb4ee6a4SAndroid Build Coastguard Worker } 289*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::LOCAL_TIMER, data); 290*bb4ee6a4SAndroid Build Coastguard Worker } 291*bb4ee6a4SAndroid Build Coastguard Worker _ => { 292*bb4ee6a4SAndroid Build Coastguard Worker // TODO(srichman): Inject a GP into the guest. 293*bb4ee6a4SAndroid Build Coastguard Worker } 294*bb4ee6a4SAndroid Build Coastguard Worker } 295*bb4ee6a4SAndroid Build Coastguard Worker msg 296*bb4ee6a4SAndroid Build Coastguard Worker } 297*bb4ee6a4SAndroid Build Coastguard Worker 298*bb4ee6a4SAndroid Build Coastguard Worker /// If `dest` specifies a single destination APIC that can be determined quickly without calling 299*bb4ee6a4SAndroid Build Coastguard Worker /// `match_dest` on each APIC, then return the destination APIC ID, otherwise return None. single_dest_fast(dest: &InterruptDestination) -> Option<u8>300*bb4ee6a4SAndroid Build Coastguard Worker pub fn single_dest_fast(dest: &InterruptDestination) -> Option<u8> { 301*bb4ee6a4SAndroid Build Coastguard Worker if dest.shorthand == DestinationShorthand::Self_ { 302*bb4ee6a4SAndroid Build Coastguard Worker Some(dest.source_id) 303*bb4ee6a4SAndroid Build Coastguard Worker } else if dest.shorthand == DestinationShorthand::None 304*bb4ee6a4SAndroid Build Coastguard Worker && dest.mode == DestinationMode::Physical 305*bb4ee6a4SAndroid Build Coastguard Worker && dest.dest_id != PHYSICAL_BROADCAST_ADDRESS 306*bb4ee6a4SAndroid Build Coastguard Worker { 307*bb4ee6a4SAndroid Build Coastguard Worker Some(dest.dest_id) 308*bb4ee6a4SAndroid Build Coastguard Worker } else { 309*bb4ee6a4SAndroid Build Coastguard Worker None 310*bb4ee6a4SAndroid Build Coastguard Worker } 311*bb4ee6a4SAndroid Build Coastguard Worker } 312*bb4ee6a4SAndroid Build Coastguard Worker 313*bb4ee6a4SAndroid Build Coastguard Worker /// Returns true if this APIC is one of the destinations of the interrupt `dest`. match_dest(&self, dest: &InterruptDestination) -> bool314*bb4ee6a4SAndroid Build Coastguard Worker pub fn match_dest(&self, dest: &InterruptDestination) -> bool { 315*bb4ee6a4SAndroid Build Coastguard Worker match dest.shorthand { 316*bb4ee6a4SAndroid Build Coastguard Worker DestinationShorthand::All => true, 317*bb4ee6a4SAndroid Build Coastguard Worker DestinationShorthand::AllExcludingSelf => dest.source_id != self.id, 318*bb4ee6a4SAndroid Build Coastguard Worker DestinationShorthand::Self_ => dest.source_id == self.id, 319*bb4ee6a4SAndroid Build Coastguard Worker DestinationShorthand::None => match dest.mode { 320*bb4ee6a4SAndroid Build Coastguard Worker DestinationMode::Physical => { 321*bb4ee6a4SAndroid Build Coastguard Worker dest.dest_id == PHYSICAL_BROADCAST_ADDRESS || dest.dest_id == self.id 322*bb4ee6a4SAndroid Build Coastguard Worker } 323*bb4ee6a4SAndroid Build Coastguard Worker DestinationMode::Logical => self.matches_logical_address(dest.dest_id), 324*bb4ee6a4SAndroid Build Coastguard Worker }, 325*bb4ee6a4SAndroid Build Coastguard Worker } 326*bb4ee6a4SAndroid Build Coastguard Worker } 327*bb4ee6a4SAndroid Build Coastguard Worker 328*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the processor priority register. get_processor_priority(&self) -> u8329*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_processor_priority(&self) -> u8 { 330*bb4ee6a4SAndroid Build Coastguard Worker // From 10.8 in the manual: 331*bb4ee6a4SAndroid Build Coastguard Worker // "PPR[7:4] (the processor-priority class) the maximum of TPR[7:4] (the task-priority 332*bb4ee6a4SAndroid Build Coastguard Worker // class) and ISRV[7:4] (the priority of the highest priority interrupt in service). 333*bb4ee6a4SAndroid Build Coastguard Worker // PPR[3:0] (the processor-priority sub-class) is determined as follows: 334*bb4ee6a4SAndroid Build Coastguard Worker // - If TPR[7:4] > ISRV[7:4], PPR[3:0] is TPR[3:0] (the task-priority sub-class). 335*bb4ee6a4SAndroid Build Coastguard Worker // - If TPR[7:4] < ISRV[7:4], PPR[3:0] is 0. 336*bb4ee6a4SAndroid Build Coastguard Worker // - If TPR[7:4] = ISRV[7:4], PPR[3:0] may be either TPR[3:0] or 0. The actual behavior 337*bb4ee6a4SAndroid Build Coastguard Worker // is model-specific." 338*bb4ee6a4SAndroid Build Coastguard Worker let tpr = self.regs[Reg::TPR]; 339*bb4ee6a4SAndroid Build Coastguard Worker let isrv = self.highest_bit_in_vector(VectorReg::Isr).unwrap_or(0); 340*bb4ee6a4SAndroid Build Coastguard Worker if tpr >> 4 >= isrv >> 4 { 341*bb4ee6a4SAndroid Build Coastguard Worker tpr 342*bb4ee6a4SAndroid Build Coastguard Worker } else { 343*bb4ee6a4SAndroid Build Coastguard Worker isrv & !0xF 344*bb4ee6a4SAndroid Build Coastguard Worker } 345*bb4ee6a4SAndroid Build Coastguard Worker } 346*bb4ee6a4SAndroid Build Coastguard Worker 347*bb4ee6a4SAndroid Build Coastguard Worker /// Enqueues an interrupt to be delivered to this APIC's vcpu. accept_irq(&mut self, i: &InterruptData)348*bb4ee6a4SAndroid Build Coastguard Worker pub fn accept_irq(&mut self, i: &InterruptData) { 349*bb4ee6a4SAndroid Build Coastguard Worker match i.delivery { 350*bb4ee6a4SAndroid Build Coastguard Worker DeliveryMode::Fixed | DeliveryMode::Lowest => { 351*bb4ee6a4SAndroid Build Coastguard Worker self.set_vector_bit(VectorReg::Irr, i.vector); 352*bb4ee6a4SAndroid Build Coastguard Worker if i.trigger == TriggerMode::Level { 353*bb4ee6a4SAndroid Build Coastguard Worker self.set_vector_bit(VectorReg::Tmr, i.vector); 354*bb4ee6a4SAndroid Build Coastguard Worker } else { 355*bb4ee6a4SAndroid Build Coastguard Worker self.clear_vector_bit(VectorReg::Tmr, i.vector); 356*bb4ee6a4SAndroid Build Coastguard Worker } 357*bb4ee6a4SAndroid Build Coastguard Worker self.mp_state = MPState::Runnable; 358*bb4ee6a4SAndroid Build Coastguard Worker } 359*bb4ee6a4SAndroid Build Coastguard Worker DeliveryMode::Startup => self.sipi = Some(i.vector), 360*bb4ee6a4SAndroid Build Coastguard Worker DeliveryMode::Init => { 361*bb4ee6a4SAndroid Build Coastguard Worker if i.level == Level::Assert { 362*bb4ee6a4SAndroid Build Coastguard Worker self.init = true; 363*bb4ee6a4SAndroid Build Coastguard Worker } 364*bb4ee6a4SAndroid Build Coastguard Worker } 365*bb4ee6a4SAndroid Build Coastguard Worker DeliveryMode::NMI => self.nmis += 1, 366*bb4ee6a4SAndroid Build Coastguard Worker DeliveryMode::External => warn!("APIC doesn't handle external interrupts, dropping"), 367*bb4ee6a4SAndroid Build Coastguard Worker DeliveryMode::RemoteRead => { 368*bb4ee6a4SAndroid Build Coastguard Worker // This type of interrupt is no longer supported or documented by Intel, but Windows 369*bb4ee6a4SAndroid Build Coastguard Worker // still issues it, and we ignore it. 370*bb4ee6a4SAndroid Build Coastguard Worker } 371*bb4ee6a4SAndroid Build Coastguard Worker DeliveryMode::SMI => warn!("APIC doesn't handle SMIs, dropping interrupt"), 372*bb4ee6a4SAndroid Build Coastguard Worker } 373*bb4ee6a4SAndroid Build Coastguard Worker } 374*bb4ee6a4SAndroid Build Coastguard Worker 375*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the highest-priority vector in the IRR that has high enough priority to be serviced 376*bb4ee6a4SAndroid Build Coastguard Worker /// (i.e., its priority class is greater than the current processor priority class). If `clear` 377*bb4ee6a4SAndroid Build Coastguard Worker /// is true, the IRR bit for that vector is cleared and the ISR bit is set. inject_interrupt(&mut self, clear: bool) -> Option<Vector>378*bb4ee6a4SAndroid Build Coastguard Worker fn inject_interrupt(&mut self, clear: bool) -> Option<Vector> { 379*bb4ee6a4SAndroid Build Coastguard Worker let irrv = self.highest_bit_in_vector(VectorReg::Irr).unwrap_or(0); 380*bb4ee6a4SAndroid Build Coastguard Worker // Only the processor priority class bits (PPR[7:4]) are used to decide if the vector has 381*bb4ee6a4SAndroid Build Coastguard Worker // priority to interrupt. 382*bb4ee6a4SAndroid Build Coastguard Worker if irrv >> 4 > self.get_processor_priority() >> 4 { 383*bb4ee6a4SAndroid Build Coastguard Worker if clear { 384*bb4ee6a4SAndroid Build Coastguard Worker self.clear_vector_bit(VectorReg::Irr, irrv); 385*bb4ee6a4SAndroid Build Coastguard Worker self.set_vector_bit(VectorReg::Isr, irrv); 386*bb4ee6a4SAndroid Build Coastguard Worker } 387*bb4ee6a4SAndroid Build Coastguard Worker Some(irrv) 388*bb4ee6a4SAndroid Build Coastguard Worker } else { 389*bb4ee6a4SAndroid Build Coastguard Worker None 390*bb4ee6a4SAndroid Build Coastguard Worker } 391*bb4ee6a4SAndroid Build Coastguard Worker } 392*bb4ee6a4SAndroid Build Coastguard Worker 393*bb4ee6a4SAndroid Build Coastguard Worker /// Parses data from the Interrupt Command Register into an interrupt. decode_icr(&mut self) -> Interrupt394*bb4ee6a4SAndroid Build Coastguard Worker fn decode_icr(&mut self) -> Interrupt { 395*bb4ee6a4SAndroid Build Coastguard Worker let hi = self.get_reg(Reg::INTERRUPT_COMMAND_HI) as u64; 396*bb4ee6a4SAndroid Build Coastguard Worker let lo = self.get_reg(Reg::INTERRUPT_COMMAND_LO) as u64; 397*bb4ee6a4SAndroid Build Coastguard Worker let icr = hi << 32 | lo; 398*bb4ee6a4SAndroid Build Coastguard Worker let mut command = InterruptCommand::new(); 399*bb4ee6a4SAndroid Build Coastguard Worker command.set(0, 64, icr); 400*bb4ee6a4SAndroid Build Coastguard Worker Interrupt { 401*bb4ee6a4SAndroid Build Coastguard Worker dest: InterruptDestination { 402*bb4ee6a4SAndroid Build Coastguard Worker source_id: self.id, 403*bb4ee6a4SAndroid Build Coastguard Worker dest_id: command.get_destination(), 404*bb4ee6a4SAndroid Build Coastguard Worker shorthand: command.get_shorthand(), 405*bb4ee6a4SAndroid Build Coastguard Worker mode: command.get_destination_mode(), 406*bb4ee6a4SAndroid Build Coastguard Worker }, 407*bb4ee6a4SAndroid Build Coastguard Worker data: InterruptData { 408*bb4ee6a4SAndroid Build Coastguard Worker vector: command.get_vector(), 409*bb4ee6a4SAndroid Build Coastguard Worker delivery: command.get_delivery(), 410*bb4ee6a4SAndroid Build Coastguard Worker trigger: command.get_trigger(), 411*bb4ee6a4SAndroid Build Coastguard Worker level: command.get_level(), 412*bb4ee6a4SAndroid Build Coastguard Worker }, 413*bb4ee6a4SAndroid Build Coastguard Worker } 414*bb4ee6a4SAndroid Build Coastguard Worker } 415*bb4ee6a4SAndroid Build Coastguard Worker 416*bb4ee6a4SAndroid Build Coastguard Worker /// Returns true if the APIC is software-enabled, false if it's software-disabled. enabled(&self) -> bool417*bb4ee6a4SAndroid Build Coastguard Worker fn enabled(&self) -> bool { 418*bb4ee6a4SAndroid Build Coastguard Worker self.get_reg(Reg::SPURIOUS_INT) & SOFTWARE_ENABLE != 0 419*bb4ee6a4SAndroid Build Coastguard Worker } 420*bb4ee6a4SAndroid Build Coastguard Worker 421*bb4ee6a4SAndroid Build Coastguard Worker /// Sets or unsets the software enabled bit in the Spurious Int register. set_enabled(&mut self, enable: bool)422*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_enabled(&mut self, enable: bool) { 423*bb4ee6a4SAndroid Build Coastguard Worker let mut val = self.get_reg(Reg::SPURIOUS_INT); 424*bb4ee6a4SAndroid Build Coastguard Worker if enable { 425*bb4ee6a4SAndroid Build Coastguard Worker val |= SOFTWARE_ENABLE; 426*bb4ee6a4SAndroid Build Coastguard Worker } else { 427*bb4ee6a4SAndroid Build Coastguard Worker val &= !SOFTWARE_ENABLE; 428*bb4ee6a4SAndroid Build Coastguard Worker } 429*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::SPURIOUS_INT, val); 430*bb4ee6a4SAndroid Build Coastguard Worker } 431*bb4ee6a4SAndroid Build Coastguard Worker 432*bb4ee6a4SAndroid Build Coastguard Worker /// Gets pending interrupts to be injected into this APIC's vcpu. The interrupts returned are 433*bb4ee6a4SAndroid Build Coastguard Worker /// cleared from the APIC. `vcpu_ready` indicates if the vcpu is ready to receive fixed 434*bb4ee6a4SAndroid Build Coastguard Worker /// interrupts (i.e., if the vcpu's interrupt window is open, IF flag is set, and the PIC hasn't 435*bb4ee6a4SAndroid Build Coastguard Worker /// already injected an interrupt). get_pending_irqs(&mut self, vcpu_ready: bool) -> PendingInterrupts436*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_pending_irqs(&mut self, vcpu_ready: bool) -> PendingInterrupts { 437*bb4ee6a4SAndroid Build Coastguard Worker let (fixed, needs_window) = if !self.enabled() { 438*bb4ee6a4SAndroid Build Coastguard Worker (None, false) 439*bb4ee6a4SAndroid Build Coastguard Worker } else { 440*bb4ee6a4SAndroid Build Coastguard Worker match self.inject_interrupt(vcpu_ready) { 441*bb4ee6a4SAndroid Build Coastguard Worker Some(vector) if vcpu_ready => { 442*bb4ee6a4SAndroid Build Coastguard Worker let has_second_interrupt = self.inject_interrupt(false).is_some(); 443*bb4ee6a4SAndroid Build Coastguard Worker (Some(vector), has_second_interrupt) 444*bb4ee6a4SAndroid Build Coastguard Worker } 445*bb4ee6a4SAndroid Build Coastguard Worker Some(_) if !vcpu_ready => (None, true), 446*bb4ee6a4SAndroid Build Coastguard Worker None => (None, false), 447*bb4ee6a4SAndroid Build Coastguard Worker _ => unreachable!(), 448*bb4ee6a4SAndroid Build Coastguard Worker } 449*bb4ee6a4SAndroid Build Coastguard Worker }; 450*bb4ee6a4SAndroid Build Coastguard Worker 451*bb4ee6a4SAndroid Build Coastguard Worker let nmis = self.nmis; 452*bb4ee6a4SAndroid Build Coastguard Worker self.nmis = 0; 453*bb4ee6a4SAndroid Build Coastguard Worker 454*bb4ee6a4SAndroid Build Coastguard Worker let init = self.init; 455*bb4ee6a4SAndroid Build Coastguard Worker self.init = false; 456*bb4ee6a4SAndroid Build Coastguard Worker 457*bb4ee6a4SAndroid Build Coastguard Worker let startup = self.sipi; 458*bb4ee6a4SAndroid Build Coastguard Worker self.sipi = None; 459*bb4ee6a4SAndroid Build Coastguard Worker 460*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 461*bb4ee6a4SAndroid Build Coastguard Worker fixed, 462*bb4ee6a4SAndroid Build Coastguard Worker nmis, 463*bb4ee6a4SAndroid Build Coastguard Worker init, 464*bb4ee6a4SAndroid Build Coastguard Worker startup, 465*bb4ee6a4SAndroid Build Coastguard Worker needs_window, 466*bb4ee6a4SAndroid Build Coastguard Worker } 467*bb4ee6a4SAndroid Build Coastguard Worker } 468*bb4ee6a4SAndroid Build Coastguard Worker 469*bb4ee6a4SAndroid Build Coastguard Worker /// Resets the APIC to its initial state. Used for initializing a new APIC and when the vcpu 470*bb4ee6a4SAndroid Build Coastguard Worker /// receives an INIT. load_reset_state(&mut self)471*bb4ee6a4SAndroid Build Coastguard Worker pub fn load_reset_state(&mut self) { 472*bb4ee6a4SAndroid Build Coastguard Worker for reg in self.regs.iter_mut() { 473*bb4ee6a4SAndroid Build Coastguard Worker *reg = 0; 474*bb4ee6a4SAndroid Build Coastguard Worker } 475*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::DESTINATION_FORMAT, 0xFFFFFFFF); 476*bb4ee6a4SAndroid Build Coastguard Worker 477*bb4ee6a4SAndroid Build Coastguard Worker // All local interrupts start out masked. 478*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::LOCAL_INT_0, LOCAL_VECTOR_MASKED); 479*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::LOCAL_INT_1, LOCAL_VECTOR_MASKED); 480*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::LOCAL_THERMAL, LOCAL_VECTOR_MASKED); 481*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::LOCAL_PERF, LOCAL_VECTOR_MASKED); 482*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::LOCAL_ERROR, LOCAL_VECTOR_MASKED); 483*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::LOCAL_TIMER, LOCAL_VECTOR_MASKED); 484*bb4ee6a4SAndroid Build Coastguard Worker self.clear_timer(); 485*bb4ee6a4SAndroid Build Coastguard Worker 486*bb4ee6a4SAndroid Build Coastguard Worker let mut version = VersionRegister::new(); 487*bb4ee6a4SAndroid Build Coastguard Worker version.set_version(VERSION); 488*bb4ee6a4SAndroid Build Coastguard Worker version.set_max_lvt(MAX_LVT); 489*bb4ee6a4SAndroid Build Coastguard Worker version.set_eoi_broadcast_suppression(1); 490*bb4ee6a4SAndroid Build Coastguard Worker let bits = version.get(0, 32) as u32; 491*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::VERSION, bits); 492*bb4ee6a4SAndroid Build Coastguard Worker 493*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::ID, (self.id as u32) << 24); 494*bb4ee6a4SAndroid Build Coastguard Worker 495*bb4ee6a4SAndroid Build Coastguard Worker // The apic starts out software disabled (Spurious Int bit 8 is unset). 496*bb4ee6a4SAndroid Build Coastguard Worker self.set_reg(Reg::SPURIOUS_INT, 0xFF); 497*bb4ee6a4SAndroid Build Coastguard Worker } 498*bb4ee6a4SAndroid Build Coastguard Worker debug_status(&self) -> String499*bb4ee6a4SAndroid Build Coastguard Worker pub fn debug_status(&self) -> String { 500*bb4ee6a4SAndroid Build Coastguard Worker let mut irr = [0u32; 8]; 501*bb4ee6a4SAndroid Build Coastguard Worker let mut isr = [0u32; 8]; 502*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..8 { 503*bb4ee6a4SAndroid Build Coastguard Worker irr[i] = self.get_reg(Reg::IRR + i * REG_ALIGN_BYTES); 504*bb4ee6a4SAndroid Build Coastguard Worker isr[i] = self.get_reg(Reg::ISR + i * REG_ALIGN_BYTES); 505*bb4ee6a4SAndroid Build Coastguard Worker } 506*bb4ee6a4SAndroid Build Coastguard Worker let irrv = self.highest_bit_in_vector(VectorReg::Irr).unwrap_or(0); 507*bb4ee6a4SAndroid Build Coastguard Worker let isrv = self.highest_bit_in_vector(VectorReg::Isr).unwrap_or(0); 508*bb4ee6a4SAndroid Build Coastguard Worker let timer = self 509*bb4ee6a4SAndroid Build Coastguard Worker .timer_length 510*bb4ee6a4SAndroid Build Coastguard Worker .map(|d| format!("{}ns", d.as_nanos())) 511*bb4ee6a4SAndroid Build Coastguard Worker .unwrap_or("None".to_string()); 512*bb4ee6a4SAndroid Build Coastguard Worker 513*bb4ee6a4SAndroid Build Coastguard Worker format!( 514*bb4ee6a4SAndroid Build Coastguard Worker "enabled={} irr={:?} irrv={} isr={:?} isrv={} irrv_prio={} proc_prio={}, timer={}", 515*bb4ee6a4SAndroid Build Coastguard Worker self.enabled(), 516*bb4ee6a4SAndroid Build Coastguard Worker irr, 517*bb4ee6a4SAndroid Build Coastguard Worker irrv, 518*bb4ee6a4SAndroid Build Coastguard Worker isr, 519*bb4ee6a4SAndroid Build Coastguard Worker isrv, 520*bb4ee6a4SAndroid Build Coastguard Worker irrv >> 4, 521*bb4ee6a4SAndroid Build Coastguard Worker self.get_processor_priority() >> 4, 522*bb4ee6a4SAndroid Build Coastguard Worker timer, 523*bb4ee6a4SAndroid Build Coastguard Worker ) 524*bb4ee6a4SAndroid Build Coastguard Worker } 525*bb4ee6a4SAndroid Build Coastguard Worker 526*bb4ee6a4SAndroid Build Coastguard Worker /// Callback to be called by a timer worker when the timer expires. handle_timer_expiration(&mut self)527*bb4ee6a4SAndroid Build Coastguard Worker pub fn handle_timer_expiration(&mut self) { 528*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.timer.mark_waited() { 529*bb4ee6a4SAndroid Build Coastguard Worker error!("APIC timer wait unexpectedly failed: {}", e); 530*bb4ee6a4SAndroid Build Coastguard Worker return; 531*bb4ee6a4SAndroid Build Coastguard Worker } 532*bb4ee6a4SAndroid Build Coastguard Worker self.last_tick = Instant::now(); 533*bb4ee6a4SAndroid Build Coastguard Worker let local_timer = self.get_reg(Reg::LOCAL_TIMER); 534*bb4ee6a4SAndroid Build Coastguard Worker let is_masked = local_timer & LOCAL_VECTOR_MASKED != 0; 535*bb4ee6a4SAndroid Build Coastguard Worker if is_masked || self.timer_length.is_none() { 536*bb4ee6a4SAndroid Build Coastguard Worker return; 537*bb4ee6a4SAndroid Build Coastguard Worker } 538*bb4ee6a4SAndroid Build Coastguard Worker // Low 8 bits are the vector. 539*bb4ee6a4SAndroid Build Coastguard Worker let vector = local_timer as u8; 540*bb4ee6a4SAndroid Build Coastguard Worker self.accept_irq(&InterruptData { 541*bb4ee6a4SAndroid Build Coastguard Worker vector, 542*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 543*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 544*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Deassert, 545*bb4ee6a4SAndroid Build Coastguard Worker }); 546*bb4ee6a4SAndroid Build Coastguard Worker } 547*bb4ee6a4SAndroid Build Coastguard Worker 548*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the first 4 bytes of the register that starts at `offset`. get_reg(&self, offset: usize) -> u32549*bb4ee6a4SAndroid Build Coastguard Worker fn get_reg(&self, offset: usize) -> u32 { 550*bb4ee6a4SAndroid Build Coastguard Worker let bytes = &self.regs[offset..offset + 4]; 551*bb4ee6a4SAndroid Build Coastguard Worker u32::from_le_bytes(bytes.try_into().unwrap()) 552*bb4ee6a4SAndroid Build Coastguard Worker } 553*bb4ee6a4SAndroid Build Coastguard Worker 554*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the first 4 bytes of the register that starts at `offset` to `val`. set_reg(&mut self, offset: usize, val: u32)555*bb4ee6a4SAndroid Build Coastguard Worker fn set_reg(&mut self, offset: usize, val: u32) { 556*bb4ee6a4SAndroid Build Coastguard Worker self.regs[offset..offset + 4].copy_from_slice(&val.to_le_bytes()); 557*bb4ee6a4SAndroid Build Coastguard Worker } 558*bb4ee6a4SAndroid Build Coastguard Worker 559*bb4ee6a4SAndroid Build Coastguard Worker /// Finds the bit for `vector` in vector bitmap register `reg`. 560*bb4ee6a4SAndroid Build Coastguard Worker /// Returns `(index, bitmask)` where `index` is the index of the register byte for `vector`, and 561*bb4ee6a4SAndroid Build Coastguard Worker /// `bitmask` has one bit set for the `vector` bit within that byte. reg_bit_for_vector(reg: VectorReg, vector: Vector) -> (usize, u8)562*bb4ee6a4SAndroid Build Coastguard Worker fn reg_bit_for_vector(reg: VectorReg, vector: Vector) -> (usize, u8) { 563*bb4ee6a4SAndroid Build Coastguard Worker let vector = vector as usize; 564*bb4ee6a4SAndroid Build Coastguard Worker // First 3 bits indicate which 16-byte aligned register 565*bb4ee6a4SAndroid Build Coastguard Worker // Next 2 bits indicate which byte in that register 566*bb4ee6a4SAndroid Build Coastguard Worker // Last 3 bits indicate which bit in that byte. 567*bb4ee6a4SAndroid Build Coastguard Worker let index = (reg as usize) + 0x10 * (vector >> 5) + ((vector >> 3) & 0x3); 568*bb4ee6a4SAndroid Build Coastguard Worker let bitmask = 1 << (vector & 0x7); 569*bb4ee6a4SAndroid Build Coastguard Worker (index, bitmask) 570*bb4ee6a4SAndroid Build Coastguard Worker } 571*bb4ee6a4SAndroid Build Coastguard Worker set_vector_bit(&mut self, reg: VectorReg, vector: Vector)572*bb4ee6a4SAndroid Build Coastguard Worker fn set_vector_bit(&mut self, reg: VectorReg, vector: Vector) { 573*bb4ee6a4SAndroid Build Coastguard Worker let (reg, bitmask) = Self::reg_bit_for_vector(reg, vector); 574*bb4ee6a4SAndroid Build Coastguard Worker self.regs[reg] |= bitmask; 575*bb4ee6a4SAndroid Build Coastguard Worker } 576*bb4ee6a4SAndroid Build Coastguard Worker clear_vector_bit(&mut self, reg: VectorReg, vector: Vector)577*bb4ee6a4SAndroid Build Coastguard Worker fn clear_vector_bit(&mut self, reg: VectorReg, vector: Vector) { 578*bb4ee6a4SAndroid Build Coastguard Worker let (reg, bitmask) = Self::reg_bit_for_vector(reg, vector); 579*bb4ee6a4SAndroid Build Coastguard Worker self.regs[reg] &= !bitmask; 580*bb4ee6a4SAndroid Build Coastguard Worker } 581*bb4ee6a4SAndroid Build Coastguard Worker 582*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the vector of the highest bit set in `reg`. highest_bit_in_vector(&self, reg: VectorReg) -> Option<Vector>583*bb4ee6a4SAndroid Build Coastguard Worker fn highest_bit_in_vector(&self, reg: VectorReg) -> Option<Vector> { 584*bb4ee6a4SAndroid Build Coastguard Worker let reg = reg as usize; 585*bb4ee6a4SAndroid Build Coastguard Worker for i in (0..8).rev() { 586*bb4ee6a4SAndroid Build Coastguard Worker let val = self.get_reg(reg + i * REG_ALIGN_BYTES); 587*bb4ee6a4SAndroid Build Coastguard Worker if val != 0 { 588*bb4ee6a4SAndroid Build Coastguard Worker let msb_set = 31 - val.leading_zeros() as u8; 589*bb4ee6a4SAndroid Build Coastguard Worker return Some(msb_set + 32 * i as u8); 590*bb4ee6a4SAndroid Build Coastguard Worker } 591*bb4ee6a4SAndroid Build Coastguard Worker } 592*bb4ee6a4SAndroid Build Coastguard Worker None 593*bb4ee6a4SAndroid Build Coastguard Worker } 594*bb4ee6a4SAndroid Build Coastguard Worker 595*bb4ee6a4SAndroid Build Coastguard Worker /// Returns true if this apic is a possible destination for the logical address `dest`. matches_logical_address(&self, dest: u8) -> bool596*bb4ee6a4SAndroid Build Coastguard Worker fn matches_logical_address(&self, dest: u8) -> bool { 597*bb4ee6a4SAndroid Build Coastguard Worker let bits = self.get_reg(Reg::DESTINATION_FORMAT) as u64; 598*bb4ee6a4SAndroid Build Coastguard Worker let mut format = DestinationFormat::new(); 599*bb4ee6a4SAndroid Build Coastguard Worker format.set(0, 32, bits); 600*bb4ee6a4SAndroid Build Coastguard Worker let model = format.get_model(); 601*bb4ee6a4SAndroid Build Coastguard Worker 602*bb4ee6a4SAndroid Build Coastguard Worker let bits = self.get_reg(Reg::LOGICAL_DESTINATION) as u64; 603*bb4ee6a4SAndroid Build Coastguard Worker let mut logical_dest = LogicalDestination::new(); 604*bb4ee6a4SAndroid Build Coastguard Worker logical_dest.set(0, 32, bits); 605*bb4ee6a4SAndroid Build Coastguard Worker let local_logical_id = logical_dest.get_logical_id(); 606*bb4ee6a4SAndroid Build Coastguard Worker 607*bb4ee6a4SAndroid Build Coastguard Worker match model { 608*bb4ee6a4SAndroid Build Coastguard Worker DESTINATION_FORMAT_FLAT => dest & local_logical_id != 0, 609*bb4ee6a4SAndroid Build Coastguard Worker DESTINATION_FORMAT_CLUSTER => { 610*bb4ee6a4SAndroid Build Coastguard Worker error!("Cluster-mode APIC logical destinations unsupported"); 611*bb4ee6a4SAndroid Build Coastguard Worker false 612*bb4ee6a4SAndroid Build Coastguard Worker } 613*bb4ee6a4SAndroid Build Coastguard Worker _ => { 614*bb4ee6a4SAndroid Build Coastguard Worker error!("Invalid APIC logical destination format {}", model); 615*bb4ee6a4SAndroid Build Coastguard Worker false 616*bb4ee6a4SAndroid Build Coastguard Worker } 617*bb4ee6a4SAndroid Build Coastguard Worker } 618*bb4ee6a4SAndroid Build Coastguard Worker } 619*bb4ee6a4SAndroid Build Coastguard Worker get_timer_divide_control(&self) -> u32620*bb4ee6a4SAndroid Build Coastguard Worker fn get_timer_divide_control(&self) -> u32 { 621*bb4ee6a4SAndroid Build Coastguard Worker let div_control = self.get_reg(Reg::TIMER_DIVIDE_CONTROL) as usize & 0xF; 622*bb4ee6a4SAndroid Build Coastguard Worker TIMER_DIVIDE_TABLE[div_control] 623*bb4ee6a4SAndroid Build Coastguard Worker } 624*bb4ee6a4SAndroid Build Coastguard Worker start_timer(&mut self)625*bb4ee6a4SAndroid Build Coastguard Worker fn start_timer(&mut self) { 626*bb4ee6a4SAndroid Build Coastguard Worker self.clear_timer(); 627*bb4ee6a4SAndroid Build Coastguard Worker let initial_count = self.get_reg(Reg::TIMER_INITIAL_COUNT); 628*bb4ee6a4SAndroid Build Coastguard Worker if initial_count == 0 { 629*bb4ee6a4SAndroid Build Coastguard Worker return; 630*bb4ee6a4SAndroid Build Coastguard Worker } 631*bb4ee6a4SAndroid Build Coastguard Worker let length = self.cycle_length * initial_count * self.get_timer_divide_control(); 632*bb4ee6a4SAndroid Build Coastguard Worker let mode = self.get_reg(Reg::LOCAL_TIMER) & TIMER_MODE_MASK; 633*bb4ee6a4SAndroid Build Coastguard Worker match mode { 634*bb4ee6a4SAndroid Build Coastguard Worker TIMER_MODE_ONE_SHOT => { 635*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.timer.reset_oneshot(length) { 636*bb4ee6a4SAndroid Build Coastguard Worker error!("Failed to reset APIC timer to one-shot({:?}) {}", length, e); 637*bb4ee6a4SAndroid Build Coastguard Worker return; 638*bb4ee6a4SAndroid Build Coastguard Worker } 639*bb4ee6a4SAndroid Build Coastguard Worker } 640*bb4ee6a4SAndroid Build Coastguard Worker TIMER_MODE_PERIODIC => { 641*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.timer.reset_repeating(length) { 642*bb4ee6a4SAndroid Build Coastguard Worker error!( 643*bb4ee6a4SAndroid Build Coastguard Worker "Failed to reset APIC timer to repeating({:?}) {}", 644*bb4ee6a4SAndroid Build Coastguard Worker length, e 645*bb4ee6a4SAndroid Build Coastguard Worker ); 646*bb4ee6a4SAndroid Build Coastguard Worker return; 647*bb4ee6a4SAndroid Build Coastguard Worker } 648*bb4ee6a4SAndroid Build Coastguard Worker } 649*bb4ee6a4SAndroid Build Coastguard Worker TIMER_MODE_TSC_DEADLINE => { 650*bb4ee6a4SAndroid Build Coastguard Worker warn!("APIC TSC-deadline timer not supported"); 651*bb4ee6a4SAndroid Build Coastguard Worker return; 652*bb4ee6a4SAndroid Build Coastguard Worker } 653*bb4ee6a4SAndroid Build Coastguard Worker _ => { 654*bb4ee6a4SAndroid Build Coastguard Worker error!("Invalid APIC timer mode 0x{:X}", mode); 655*bb4ee6a4SAndroid Build Coastguard Worker return; 656*bb4ee6a4SAndroid Build Coastguard Worker } 657*bb4ee6a4SAndroid Build Coastguard Worker }; 658*bb4ee6a4SAndroid Build Coastguard Worker 659*bb4ee6a4SAndroid Build Coastguard Worker self.last_tick = Instant::now(); 660*bb4ee6a4SAndroid Build Coastguard Worker self.timer_length = Some(length); 661*bb4ee6a4SAndroid Build Coastguard Worker } 662*bb4ee6a4SAndroid Build Coastguard Worker clear_timer(&mut self)663*bb4ee6a4SAndroid Build Coastguard Worker fn clear_timer(&mut self) { 664*bb4ee6a4SAndroid Build Coastguard Worker if self.timer_length.is_some() { 665*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.timer.clear() { 666*bb4ee6a4SAndroid Build Coastguard Worker error!("Failed to clear APIC timer: {}", e); 667*bb4ee6a4SAndroid Build Coastguard Worker } 668*bb4ee6a4SAndroid Build Coastguard Worker self.timer_length = None; 669*bb4ee6a4SAndroid Build Coastguard Worker } 670*bb4ee6a4SAndroid Build Coastguard Worker } 671*bb4ee6a4SAndroid Build Coastguard Worker 672*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the duration remaining until the next timer expiration. next_timer_expiration(&self) -> Duration673*bb4ee6a4SAndroid Build Coastguard Worker fn next_timer_expiration(&self) -> Duration { 674*bb4ee6a4SAndroid Build Coastguard Worker if let Some(length) = self.timer_length { 675*bb4ee6a4SAndroid Build Coastguard Worker let elapsed = self.last_tick.elapsed(); 676*bb4ee6a4SAndroid Build Coastguard Worker length.checked_sub(elapsed).unwrap_or(ZERO_DURATION) 677*bb4ee6a4SAndroid Build Coastguard Worker } else { 678*bb4ee6a4SAndroid Build Coastguard Worker ZERO_DURATION 679*bb4ee6a4SAndroid Build Coastguard Worker } 680*bb4ee6a4SAndroid Build Coastguard Worker } 681*bb4ee6a4SAndroid Build Coastguard Worker } 682*bb4ee6a4SAndroid Build Coastguard Worker 683*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for Apic { drop(&mut self)684*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) { 685*bb4ee6a4SAndroid Build Coastguard Worker self.clear_timer(); 686*bb4ee6a4SAndroid Build Coastguard Worker } 687*bb4ee6a4SAndroid Build Coastguard Worker } 688*bb4ee6a4SAndroid Build Coastguard Worker 689*bb4ee6a4SAndroid Build Coastguard Worker /// A message from an `Apic` to the `UserspaceIrqChip`. 690*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)] 691*bb4ee6a4SAndroid Build Coastguard Worker pub enum ApicBusMsg { 692*bb4ee6a4SAndroid Build Coastguard Worker /// Broadcasts end-of-interrupt for the specified vector. 693*bb4ee6a4SAndroid Build Coastguard Worker Eoi(Vector), 694*bb4ee6a4SAndroid Build Coastguard Worker /// Sends an IPI. 695*bb4ee6a4SAndroid Build Coastguard Worker Ipi(Interrupt), 696*bb4ee6a4SAndroid Build Coastguard Worker } 697*bb4ee6a4SAndroid Build Coastguard Worker 698*bb4ee6a4SAndroid Build Coastguard Worker /// Pending `Apic` interrupts to be injected into a vcpu. 699*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 700*bb4ee6a4SAndroid Build Coastguard Worker pub struct PendingInterrupts { 701*bb4ee6a4SAndroid Build Coastguard Worker /// Vector of a pending fixed interrupt. 702*bb4ee6a4SAndroid Build Coastguard Worker pub fixed: Option<Vector>, 703*bb4ee6a4SAndroid Build Coastguard Worker /// Number of pending non-maskable interrupts. 704*bb4ee6a4SAndroid Build Coastguard Worker pub nmis: u32, 705*bb4ee6a4SAndroid Build Coastguard Worker /// True if there is a pending INIT IPI. 706*bb4ee6a4SAndroid Build Coastguard Worker pub init: bool, 707*bb4ee6a4SAndroid Build Coastguard Worker /// Vector of a pending startup IPI (SIPI). 708*bb4ee6a4SAndroid Build Coastguard Worker pub startup: Option<Vector>, 709*bb4ee6a4SAndroid Build Coastguard Worker /// True if there are additional pending interrupts to delivered in the future, so an interrupt 710*bb4ee6a4SAndroid Build Coastguard Worker /// window should be requested for the vcpu. 711*bb4ee6a4SAndroid Build Coastguard Worker pub needs_window: bool, 712*bb4ee6a4SAndroid Build Coastguard Worker } 713*bb4ee6a4SAndroid Build Coastguard Worker 714*bb4ee6a4SAndroid Build Coastguard Worker /// A quick method of specifying all processors, all excluding self, or self as the destination. 715*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield] 716*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)] 717*bb4ee6a4SAndroid Build Coastguard Worker pub enum DestinationShorthand { 718*bb4ee6a4SAndroid Build Coastguard Worker None = 0b00, 719*bb4ee6a4SAndroid Build Coastguard Worker Self_ = 0b01, 720*bb4ee6a4SAndroid Build Coastguard Worker All = 0b10, 721*bb4ee6a4SAndroid Build Coastguard Worker AllExcludingSelf = 0b11, 722*bb4ee6a4SAndroid Build Coastguard Worker } 723*bb4ee6a4SAndroid Build Coastguard Worker 724*bb4ee6a4SAndroid Build Coastguard Worker /// An interrupt to be sent to one or more `Apic`s. 725*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)] 726*bb4ee6a4SAndroid Build Coastguard Worker pub struct Interrupt { 727*bb4ee6a4SAndroid Build Coastguard Worker /// Specifies the destination processors for this interrupt. 728*bb4ee6a4SAndroid Build Coastguard Worker pub dest: InterruptDestination, 729*bb4ee6a4SAndroid Build Coastguard Worker /// The vector and type of this interrupt. 730*bb4ee6a4SAndroid Build Coastguard Worker pub data: InterruptData, 731*bb4ee6a4SAndroid Build Coastguard Worker } 732*bb4ee6a4SAndroid Build Coastguard Worker 733*bb4ee6a4SAndroid Build Coastguard Worker /// Specifies the destination processors for an `Interrupt`. 734*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)] 735*bb4ee6a4SAndroid Build Coastguard Worker pub struct InterruptDestination { 736*bb4ee6a4SAndroid Build Coastguard Worker /// The APIC ID that sent this interrupt. 737*bb4ee6a4SAndroid Build Coastguard Worker pub source_id: u8, 738*bb4ee6a4SAndroid Build Coastguard Worker /// In physical destination mode, used to specify the APIC ID of the destination processor. 739*bb4ee6a4SAndroid Build Coastguard Worker /// In logical destination mode, used to specify a message destination address (MDA) that can 740*bb4ee6a4SAndroid Build Coastguard Worker /// be used to select specific processors in clusters. Only used if shorthand is None. 741*bb4ee6a4SAndroid Build Coastguard Worker pub dest_id: u8, 742*bb4ee6a4SAndroid Build Coastguard Worker /// Specifies a quick destination of all processors, all excluding self, or self. If None, 743*bb4ee6a4SAndroid Build Coastguard Worker /// then dest_id and mode are used to find the destinations. 744*bb4ee6a4SAndroid Build Coastguard Worker pub shorthand: DestinationShorthand, 745*bb4ee6a4SAndroid Build Coastguard Worker /// Specifies if physical or logical addressing is used for matching dest_id. 746*bb4ee6a4SAndroid Build Coastguard Worker pub mode: DestinationMode, 747*bb4ee6a4SAndroid Build Coastguard Worker } 748*bb4ee6a4SAndroid Build Coastguard Worker 749*bb4ee6a4SAndroid Build Coastguard Worker /// The vector and type of an `Interrupt`. 750*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)] 751*bb4ee6a4SAndroid Build Coastguard Worker pub struct InterruptData { 752*bb4ee6a4SAndroid Build Coastguard Worker /// The index in the OS's interrupt descriptor table for this interrupt. 753*bb4ee6a4SAndroid Build Coastguard Worker pub vector: Vector, 754*bb4ee6a4SAndroid Build Coastguard Worker /// The type of interrupt: fixed (regular IDT vector), NMI, startup IPI, etc. 755*bb4ee6a4SAndroid Build Coastguard Worker pub delivery: DeliveryMode, 756*bb4ee6a4SAndroid Build Coastguard Worker /// Edge- or level-triggered. 757*bb4ee6a4SAndroid Build Coastguard Worker pub trigger: TriggerMode, 758*bb4ee6a4SAndroid Build Coastguard Worker /// For level-triggered interrupts, specifies whether the line should be asserted or 759*bb4ee6a4SAndroid Build Coastguard Worker /// deasserted. 760*bb4ee6a4SAndroid Build Coastguard Worker pub level: Level, 761*bb4ee6a4SAndroid Build Coastguard Worker } 762*bb4ee6a4SAndroid Build Coastguard Worker 763*bb4ee6a4SAndroid Build Coastguard Worker impl TryFrom<&MsiAddressMessage> for InterruptDestination { 764*bb4ee6a4SAndroid Build Coastguard Worker type Error = String; 765*bb4ee6a4SAndroid Build Coastguard Worker try_from(msi: &MsiAddressMessage) -> std::result::Result<Self, Self::Error>766*bb4ee6a4SAndroid Build Coastguard Worker fn try_from(msi: &MsiAddressMessage) -> std::result::Result<Self, Self::Error> { 767*bb4ee6a4SAndroid Build Coastguard Worker if msi.get_always_0xfee() != 0xFEE { 768*bb4ee6a4SAndroid Build Coastguard Worker return Err(format!( 769*bb4ee6a4SAndroid Build Coastguard Worker "top 12 bits must be 0xFEE but are 0x{:X}", 770*bb4ee6a4SAndroid Build Coastguard Worker msi.get_always_0xfee() 771*bb4ee6a4SAndroid Build Coastguard Worker )); 772*bb4ee6a4SAndroid Build Coastguard Worker } 773*bb4ee6a4SAndroid Build Coastguard Worker // TODO(srichman): Handle redirection hint? 774*bb4ee6a4SAndroid Build Coastguard Worker Ok(InterruptDestination { 775*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 776*bb4ee6a4SAndroid Build Coastguard Worker dest_id: msi.get_destination_id(), 777*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 778*bb4ee6a4SAndroid Build Coastguard Worker mode: msi.get_destination_mode(), 779*bb4ee6a4SAndroid Build Coastguard Worker }) 780*bb4ee6a4SAndroid Build Coastguard Worker } 781*bb4ee6a4SAndroid Build Coastguard Worker } 782*bb4ee6a4SAndroid Build Coastguard Worker 783*bb4ee6a4SAndroid Build Coastguard Worker impl From<&MsiDataMessage> for InterruptData { from(msi: &MsiDataMessage) -> Self784*bb4ee6a4SAndroid Build Coastguard Worker fn from(msi: &MsiDataMessage) -> Self { 785*bb4ee6a4SAndroid Build Coastguard Worker InterruptData { 786*bb4ee6a4SAndroid Build Coastguard Worker vector: msi.get_vector(), 787*bb4ee6a4SAndroid Build Coastguard Worker delivery: msi.get_delivery_mode(), 788*bb4ee6a4SAndroid Build Coastguard Worker trigger: msi.get_trigger(), 789*bb4ee6a4SAndroid Build Coastguard Worker level: msi.get_level(), 790*bb4ee6a4SAndroid Build Coastguard Worker } 791*bb4ee6a4SAndroid Build Coastguard Worker } 792*bb4ee6a4SAndroid Build Coastguard Worker } 793*bb4ee6a4SAndroid Build Coastguard Worker 794*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield] 795*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy)] 796*bb4ee6a4SAndroid Build Coastguard Worker struct LocalInterrupt { 797*bb4ee6a4SAndroid Build Coastguard Worker vector: BitField8, 798*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 3] 799*bb4ee6a4SAndroid Build Coastguard Worker delivery_mode: DeliveryMode, 800*bb4ee6a4SAndroid Build Coastguard Worker reserved1: BitField1, 801*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 1] 802*bb4ee6a4SAndroid Build Coastguard Worker delivery_status: DeliveryStatus, 803*bb4ee6a4SAndroid Build Coastguard Worker polarity: BitField1, 804*bb4ee6a4SAndroid Build Coastguard Worker remote_irr: BitField1, 805*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 1] 806*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode, 807*bb4ee6a4SAndroid Build Coastguard Worker masked: BitField1, 808*bb4ee6a4SAndroid Build Coastguard Worker reserved2: BitField7, 809*bb4ee6a4SAndroid Build Coastguard Worker reserved3: BitField8, 810*bb4ee6a4SAndroid Build Coastguard Worker } 811*bb4ee6a4SAndroid Build Coastguard Worker 812*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield] 813*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy)] 814*bb4ee6a4SAndroid Build Coastguard Worker struct VersionRegister { 815*bb4ee6a4SAndroid Build Coastguard Worker version: BitField8, 816*bb4ee6a4SAndroid Build Coastguard Worker reserved1: BitField8, 817*bb4ee6a4SAndroid Build Coastguard Worker max_lvt: BitField8, 818*bb4ee6a4SAndroid Build Coastguard Worker eoi_broadcast_suppression: BitField1, 819*bb4ee6a4SAndroid Build Coastguard Worker reserved2: BitField7, 820*bb4ee6a4SAndroid Build Coastguard Worker } 821*bb4ee6a4SAndroid Build Coastguard Worker 822*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield] 823*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy)] 824*bb4ee6a4SAndroid Build Coastguard Worker struct DestinationFormat { 825*bb4ee6a4SAndroid Build Coastguard Worker reserved: BitField28, 826*bb4ee6a4SAndroid Build Coastguard Worker model: BitField4, 827*bb4ee6a4SAndroid Build Coastguard Worker } 828*bb4ee6a4SAndroid Build Coastguard Worker 829*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield] 830*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy)] 831*bb4ee6a4SAndroid Build Coastguard Worker struct LogicalDestination { 832*bb4ee6a4SAndroid Build Coastguard Worker reserved: BitField24, 833*bb4ee6a4SAndroid Build Coastguard Worker logical_id: BitField8, 834*bb4ee6a4SAndroid Build Coastguard Worker } 835*bb4ee6a4SAndroid Build Coastguard Worker 836*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield] 837*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy)] 838*bb4ee6a4SAndroid Build Coastguard Worker struct InterruptCommand { 839*bb4ee6a4SAndroid Build Coastguard Worker vector: BitField8, 840*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 3] 841*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode, 842*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 1] 843*bb4ee6a4SAndroid Build Coastguard Worker destination_mode: DestinationMode, 844*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 1] 845*bb4ee6a4SAndroid Build Coastguard Worker delivery_status: DeliveryStatus, 846*bb4ee6a4SAndroid Build Coastguard Worker reserved1: BitField1, 847*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 1] 848*bb4ee6a4SAndroid Build Coastguard Worker level: Level, 849*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 1] 850*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode, 851*bb4ee6a4SAndroid Build Coastguard Worker reserved2: BitField2, 852*bb4ee6a4SAndroid Build Coastguard Worker #[bits = 2] 853*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand, 854*bb4ee6a4SAndroid Build Coastguard Worker reserved3: BitField36, 855*bb4ee6a4SAndroid Build Coastguard Worker destination: BitField8, 856*bb4ee6a4SAndroid Build Coastguard Worker } 857*bb4ee6a4SAndroid Build Coastguard Worker 858*bb4ee6a4SAndroid Build Coastguard Worker struct Reg; 859*bb4ee6a4SAndroid Build Coastguard Worker 860*bb4ee6a4SAndroid Build Coastguard Worker impl Reg { 861*bb4ee6a4SAndroid Build Coastguard Worker const ID: usize = 0x20; 862*bb4ee6a4SAndroid Build Coastguard Worker const VERSION: usize = 0x30; 863*bb4ee6a4SAndroid Build Coastguard Worker const TPR: usize = 0x80; 864*bb4ee6a4SAndroid Build Coastguard Worker const PPR: usize = 0xA0; 865*bb4ee6a4SAndroid Build Coastguard Worker const EOI: usize = 0xB0; 866*bb4ee6a4SAndroid Build Coastguard Worker const LOGICAL_DESTINATION: usize = 0xD0; 867*bb4ee6a4SAndroid Build Coastguard Worker const DESTINATION_FORMAT: usize = 0xE0; 868*bb4ee6a4SAndroid Build Coastguard Worker const SPURIOUS_INT: usize = 0xF0; 869*bb4ee6a4SAndroid Build Coastguard Worker // In-service register is 0x100-0x170 870*bb4ee6a4SAndroid Build Coastguard Worker const ISR: usize = 0x100; 871*bb4ee6a4SAndroid Build Coastguard Worker // Trigger mode register is 0x180-0x1F0 872*bb4ee6a4SAndroid Build Coastguard Worker const TMR: usize = 0x180; 873*bb4ee6a4SAndroid Build Coastguard Worker // Interrupt request regsiter is 0x200-0x270 874*bb4ee6a4SAndroid Build Coastguard Worker const IRR: usize = 0x200; 875*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_CMCI: usize = 0x2F0; 876*bb4ee6a4SAndroid Build Coastguard Worker const INTERRUPT_COMMAND_LO: usize = 0x300; 877*bb4ee6a4SAndroid Build Coastguard Worker const INTERRUPT_COMMAND_HI: usize = 0x310; 878*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_TIMER: usize = 0x320; 879*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_THERMAL: usize = 0x330; 880*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_PERF: usize = 0x340; 881*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_INT_0: usize = 0x350; 882*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_INT_1: usize = 0x360; 883*bb4ee6a4SAndroid Build Coastguard Worker const LOCAL_ERROR: usize = 0x370; 884*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_INITIAL_COUNT: usize = 0x380; 885*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_CURRENT_COUNT: usize = 0x390; 886*bb4ee6a4SAndroid Build Coastguard Worker const TIMER_DIVIDE_CONTROL: usize = 0x3E0; 887*bb4ee6a4SAndroid Build Coastguard Worker } 888*bb4ee6a4SAndroid Build Coastguard Worker 889*bb4ee6a4SAndroid Build Coastguard Worker /// The APIC registers that store interrupt vector bitmaps. Each has 256 bit flags, one for each 890*bb4ee6a4SAndroid Build Coastguard Worker /// interrupt vector. The flags are spread across the first 32 bits of each of eight 16-byte APIC 891*bb4ee6a4SAndroid Build Coastguard Worker /// register slots. 892*bb4ee6a4SAndroid Build Coastguard Worker #[repr(usize)] 893*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialEq, Eq)] 894*bb4ee6a4SAndroid Build Coastguard Worker enum VectorReg { 895*bb4ee6a4SAndroid Build Coastguard Worker /// In-service register. A bit is set for each interrupt vector currently being serviced by 896*bb4ee6a4SAndroid Build Coastguard Worker /// the processor. 897*bb4ee6a4SAndroid Build Coastguard Worker Isr = Reg::ISR, 898*bb4ee6a4SAndroid Build Coastguard Worker /// Trigger mode register. Records whether interrupts are edge-triggered (bit is clear) or 899*bb4ee6a4SAndroid Build Coastguard Worker /// level-triggered (bit is set). 900*bb4ee6a4SAndroid Build Coastguard Worker Tmr = Reg::TMR, 901*bb4ee6a4SAndroid Build Coastguard Worker /// Interrupt request register. A bit is set for each interrupt vector received by the APIC 902*bb4ee6a4SAndroid Build Coastguard Worker /// but not yet serviced by the processor. 903*bb4ee6a4SAndroid Build Coastguard Worker Irr = Reg::IRR, 904*bb4ee6a4SAndroid Build Coastguard Worker } 905*bb4ee6a4SAndroid Build Coastguard Worker 906*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 907*bb4ee6a4SAndroid Build Coastguard Worker mod tests { 908*bb4ee6a4SAndroid Build Coastguard Worker use std::mem; 909*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc; 910*bb4ee6a4SAndroid Build Coastguard Worker 911*bb4ee6a4SAndroid Build Coastguard Worker use base::FakeClock; 912*bb4ee6a4SAndroid Build Coastguard Worker use base::FakeTimer; 913*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex; 914*bb4ee6a4SAndroid Build Coastguard Worker 915*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 916*bb4ee6a4SAndroid Build Coastguard Worker 917*bb4ee6a4SAndroid Build Coastguard Worker #[test] struct_size()918*bb4ee6a4SAndroid Build Coastguard Worker fn struct_size() { 919*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(4, mem::size_of::<LocalInterrupt>()); 920*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(4, mem::size_of::<VersionRegister>()); 921*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(4, mem::size_of::<DestinationFormat>()); 922*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(4, mem::size_of::<LogicalDestination>()); 923*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(8, mem::size_of::<InterruptCommand>()); 924*bb4ee6a4SAndroid Build Coastguard Worker } 925*bb4ee6a4SAndroid Build Coastguard Worker 926*bb4ee6a4SAndroid Build Coastguard Worker #[test] get_reg()927*bb4ee6a4SAndroid Build Coastguard Worker fn get_reg() { 928*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 929*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 930*bb4ee6a4SAndroid Build Coastguard Worker a.regs[0..4].copy_from_slice(&[0xFE, 0xCA, 0xAD, 0xAB]); 931*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(0), 0xABADCAFE); 932*bb4ee6a4SAndroid Build Coastguard Worker a.regs[4092..4096].copy_from_slice(&[0x0D, 0xF0, 0x1D, 0xC0]); 933*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(4092), 0xC01DF00D); 934*bb4ee6a4SAndroid Build Coastguard Worker } 935*bb4ee6a4SAndroid Build Coastguard Worker 936*bb4ee6a4SAndroid Build Coastguard Worker #[test] set_reg()937*bb4ee6a4SAndroid Build Coastguard Worker fn set_reg() { 938*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 939*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 940*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(0, 0xABADCAFE); 941*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.regs[0..4], [0xFE, 0xCA, 0xAD, 0xAB]); 942*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(4092, 0xC01DF00D); 943*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.regs[4092..4096], [0x0D, 0xF0, 0x1D, 0xC0]); 944*bb4ee6a4SAndroid Build Coastguard Worker } 945*bb4ee6a4SAndroid Build Coastguard Worker 946*bb4ee6a4SAndroid Build Coastguard Worker #[test] lapic_state()947*bb4ee6a4SAndroid Build Coastguard Worker fn lapic_state() { 948*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 949*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 950*bb4ee6a4SAndroid Build Coastguard Worker 951*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(0, 0xABADCAFE); 952*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_state().regs[0], 0xABADCAFE); 953*bb4ee6a4SAndroid Build Coastguard Worker 954*bb4ee6a4SAndroid Build Coastguard Worker let mut state = LapicState { regs: [0; 64] }; 955*bb4ee6a4SAndroid Build Coastguard Worker state.regs[63] = 0xC01DF00D; 956*bb4ee6a4SAndroid Build Coastguard Worker a.set_state(&state); 957*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.regs[1008..1012], [0x0D, 0xF0, 0x1D, 0xC0]); 958*bb4ee6a4SAndroid Build Coastguard Worker } 959*bb4ee6a4SAndroid Build Coastguard Worker 960*bb4ee6a4SAndroid Build Coastguard Worker #[test] valid_mmio()961*bb4ee6a4SAndroid Build Coastguard Worker fn valid_mmio() { 962*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 963*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(42, timer); 964*bb4ee6a4SAndroid Build Coastguard Worker 965*bb4ee6a4SAndroid Build Coastguard Worker let mut data = [0u8; 4]; 966*bb4ee6a4SAndroid Build Coastguard Worker a.read(Reg::ID as u64, &mut data); 967*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(data, [0, 0, 0, 42]); 968*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::INTERRUPT_COMMAND_HI as u64, &[0xFE, 0xCA, 0xAD, 0xAB]); 969*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::INTERRUPT_COMMAND_HI), 0xABADCAFE); 970*bb4ee6a4SAndroid Build Coastguard Worker let mut data = [0u8; 4]; 971*bb4ee6a4SAndroid Build Coastguard Worker a.read(Reg::INTERRUPT_COMMAND_HI as u64, &mut data); 972*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(data, [0xFE, 0xCA, 0xAD, 0xAB]); 973*bb4ee6a4SAndroid Build Coastguard Worker } 974*bb4ee6a4SAndroid Build Coastguard Worker 975*bb4ee6a4SAndroid Build Coastguard Worker #[test] invalid_mmio()976*bb4ee6a4SAndroid Build Coastguard Worker fn invalid_mmio() { 977*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 978*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 979*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::INTERRUPT_COMMAND_HI, 0xABADCAFE); 980*bb4ee6a4SAndroid Build Coastguard Worker 981*bb4ee6a4SAndroid Build Coastguard Worker let mut data = [0u8; 5]; 982*bb4ee6a4SAndroid Build Coastguard Worker a.read(Reg::INTERRUPT_COMMAND_HI as u64, &mut data); 983*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(data, [0; 5]); 984*bb4ee6a4SAndroid Build Coastguard Worker let mut data = [0u8; 4]; 985*bb4ee6a4SAndroid Build Coastguard Worker a.read(Reg::INTERRUPT_COMMAND_HI as u64 + 1, &mut data); 986*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(data, [0; 4]); 987*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::INTERRUPT_COMMAND_HI as u64, &[0; 3]); 988*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::INTERRUPT_COMMAND_HI), 0xABADCAFE); 989*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::INTERRUPT_COMMAND_HI as u64 + 1, &[0; 4]); 990*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::INTERRUPT_COMMAND_HI), 0xABADCAFE); 991*bb4ee6a4SAndroid Build Coastguard Worker } 992*bb4ee6a4SAndroid Build Coastguard Worker 993*bb4ee6a4SAndroid Build Coastguard Worker #[test] vector_reg()994*bb4ee6a4SAndroid Build Coastguard Worker fn vector_reg() { 995*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 996*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 997*bb4ee6a4SAndroid Build Coastguard Worker 998*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), None); 999*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 0); 1000*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0)); 1001*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 7); 1002*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(7)); 1003*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 8); 1004*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(8)); 1005*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 31); 1006*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(31)); 1007*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 32); 1008*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(32)); 1009*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 74); 1010*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(74)); 1011*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 66); 1012*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(74)); 1013*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Irr, 255); 1014*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(255)); 1015*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1016*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::IRR), 1017*bb4ee6a4SAndroid Build Coastguard Worker 0b1000_0000_0000_0000_0000_0001_1000_0001 1018*bb4ee6a4SAndroid Build Coastguard Worker ); 1019*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1020*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::IRR + 1 * REG_ALIGN_BYTES), 1021*bb4ee6a4SAndroid Build Coastguard Worker 0b0000_0000_0000_0000_0000_0000_0000_0001 1022*bb4ee6a4SAndroid Build Coastguard Worker ); 1023*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1024*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::IRR + 2 * REG_ALIGN_BYTES), 1025*bb4ee6a4SAndroid Build Coastguard Worker 0b0000_0000_0000_0000_0000_0100_0000_0100 1026*bb4ee6a4SAndroid Build Coastguard Worker ); 1027*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 3 * REG_ALIGN_BYTES), 0); 1028*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 4 * REG_ALIGN_BYTES), 0); 1029*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 5 * REG_ALIGN_BYTES), 0); 1030*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 6 * REG_ALIGN_BYTES), 0); 1031*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1032*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::IRR + 7 * REG_ALIGN_BYTES), 1033*bb4ee6a4SAndroid Build Coastguard Worker 0b1000_0000_0000_0000_0000_0000_0000_0000 1034*bb4ee6a4SAndroid Build Coastguard Worker ); 1035*bb4ee6a4SAndroid Build Coastguard Worker 1036*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Irr, 255); 1037*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(74)); 1038*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Irr, 74); 1039*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(66)); 1040*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Irr, 32); 1041*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Irr, 66); 1042*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Irr, 31); 1043*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Irr, 200); 1044*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(8)); 1045*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1046*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::IRR), 1047*bb4ee6a4SAndroid Build Coastguard Worker 0b0000_0000_0000_0000_0000_0001_1000_0001 1048*bb4ee6a4SAndroid Build Coastguard Worker ); 1049*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 1 * REG_ALIGN_BYTES), 0); 1050*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 2 * REG_ALIGN_BYTES), 0); 1051*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 3 * REG_ALIGN_BYTES), 0); 1052*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 4 * REG_ALIGN_BYTES), 0); 1053*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 5 * REG_ALIGN_BYTES), 0); 1054*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 6 * REG_ALIGN_BYTES), 0); 1055*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 7 * REG_ALIGN_BYTES), 0); 1056*bb4ee6a4SAndroid Build Coastguard Worker } 1057*bb4ee6a4SAndroid Build Coastguard Worker 1058*bb4ee6a4SAndroid Build Coastguard Worker #[test] single_dest()1059*bb4ee6a4SAndroid Build Coastguard Worker fn single_dest() { 1060*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1061*bb4ee6a4SAndroid Build Coastguard Worker Apic::single_dest_fast(&InterruptDestination { 1062*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1063*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 254, 1064*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1065*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1066*bb4ee6a4SAndroid Build Coastguard Worker }), 1067*bb4ee6a4SAndroid Build Coastguard Worker Some(254) 1068*bb4ee6a4SAndroid Build Coastguard Worker ); 1069*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1070*bb4ee6a4SAndroid Build Coastguard Worker Apic::single_dest_fast(&InterruptDestination { 1071*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1072*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 254, 1073*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::Self_, 1074*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1075*bb4ee6a4SAndroid Build Coastguard Worker }), 1076*bb4ee6a4SAndroid Build Coastguard Worker Some(0) 1077*bb4ee6a4SAndroid Build Coastguard Worker ); 1078*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1079*bb4ee6a4SAndroid Build Coastguard Worker Apic::single_dest_fast(&InterruptDestination { 1080*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1081*bb4ee6a4SAndroid Build Coastguard Worker dest_id: PHYSICAL_BROADCAST_ADDRESS, 1082*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1083*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1084*bb4ee6a4SAndroid Build Coastguard Worker }), 1085*bb4ee6a4SAndroid Build Coastguard Worker None 1086*bb4ee6a4SAndroid Build Coastguard Worker ); 1087*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1088*bb4ee6a4SAndroid Build Coastguard Worker Apic::single_dest_fast(&InterruptDestination { 1089*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1090*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 254, 1091*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::All, 1092*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1093*bb4ee6a4SAndroid Build Coastguard Worker }), 1094*bb4ee6a4SAndroid Build Coastguard Worker None 1095*bb4ee6a4SAndroid Build Coastguard Worker ); 1096*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1097*bb4ee6a4SAndroid Build Coastguard Worker Apic::single_dest_fast(&InterruptDestination { 1098*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1099*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 254, 1100*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::AllExcludingSelf, 1101*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1102*bb4ee6a4SAndroid Build Coastguard Worker }), 1103*bb4ee6a4SAndroid Build Coastguard Worker None 1104*bb4ee6a4SAndroid Build Coastguard Worker ); 1105*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1106*bb4ee6a4SAndroid Build Coastguard Worker Apic::single_dest_fast(&InterruptDestination { 1107*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1108*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 254, 1109*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1110*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Logical, 1111*bb4ee6a4SAndroid Build Coastguard Worker }), 1112*bb4ee6a4SAndroid Build Coastguard Worker None 1113*bb4ee6a4SAndroid Build Coastguard Worker ); 1114*bb4ee6a4SAndroid Build Coastguard Worker } 1115*bb4ee6a4SAndroid Build Coastguard Worker 1116*bb4ee6a4SAndroid Build Coastguard Worker #[test] match_dest()1117*bb4ee6a4SAndroid Build Coastguard Worker fn match_dest() { 1118*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1119*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(254, timer); 1120*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::LOGICAL_DESTINATION, 0b11001001 << 24); 1121*bb4ee6a4SAndroid Build Coastguard Worker 1122*bb4ee6a4SAndroid Build Coastguard Worker assert!(a.match_dest(&InterruptDestination { 1123*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1124*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 254, 1125*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1126*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1127*bb4ee6a4SAndroid Build Coastguard Worker })); 1128*bb4ee6a4SAndroid Build Coastguard Worker assert!(a.match_dest(&InterruptDestination { 1129*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1130*bb4ee6a4SAndroid Build Coastguard Worker dest_id: PHYSICAL_BROADCAST_ADDRESS, 1131*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1132*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1133*bb4ee6a4SAndroid Build Coastguard Worker })); 1134*bb4ee6a4SAndroid Build Coastguard Worker assert!(!a.match_dest(&InterruptDestination { 1135*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1136*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 77, 1137*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1138*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1139*bb4ee6a4SAndroid Build Coastguard Worker })); 1140*bb4ee6a4SAndroid Build Coastguard Worker assert!(a.match_dest(&InterruptDestination { 1141*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1142*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 0b01001000, 1143*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1144*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Logical, 1145*bb4ee6a4SAndroid Build Coastguard Worker })); 1146*bb4ee6a4SAndroid Build Coastguard Worker assert!(!a.match_dest(&InterruptDestination { 1147*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1148*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 0b00010010, 1149*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1150*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Logical, 1151*bb4ee6a4SAndroid Build Coastguard Worker })); 1152*bb4ee6a4SAndroid Build Coastguard Worker assert!(a.match_dest(&InterruptDestination { 1153*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1154*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 0, 1155*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::All, 1156*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1157*bb4ee6a4SAndroid Build Coastguard Worker })); 1158*bb4ee6a4SAndroid Build Coastguard Worker assert!(a.match_dest(&InterruptDestination { 1159*bb4ee6a4SAndroid Build Coastguard Worker source_id: 254, 1160*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 0, 1161*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::Self_, 1162*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1163*bb4ee6a4SAndroid Build Coastguard Worker })); 1164*bb4ee6a4SAndroid Build Coastguard Worker assert!(!a.match_dest(&InterruptDestination { 1165*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1166*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 0, 1167*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::Self_, 1168*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1169*bb4ee6a4SAndroid Build Coastguard Worker })); 1170*bb4ee6a4SAndroid Build Coastguard Worker assert!(a.match_dest(&InterruptDestination { 1171*bb4ee6a4SAndroid Build Coastguard Worker source_id: 0, 1172*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 0, 1173*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::AllExcludingSelf, 1174*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1175*bb4ee6a4SAndroid Build Coastguard Worker })); 1176*bb4ee6a4SAndroid Build Coastguard Worker assert!(!a.match_dest(&InterruptDestination { 1177*bb4ee6a4SAndroid Build Coastguard Worker source_id: 254, 1178*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 0, 1179*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::AllExcludingSelf, 1180*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1181*bb4ee6a4SAndroid Build Coastguard Worker })); 1182*bb4ee6a4SAndroid Build Coastguard Worker } 1183*bb4ee6a4SAndroid Build Coastguard Worker 1184*bb4ee6a4SAndroid Build Coastguard Worker #[test] processor_priority()1185*bb4ee6a4SAndroid Build Coastguard Worker fn processor_priority() { 1186*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1187*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1188*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0); 1189*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::TPR, 0xF); 1190*bb4ee6a4SAndroid Build Coastguard Worker let prio = a.get_processor_priority(); 1191*bb4ee6a4SAndroid Build Coastguard Worker // When TPR[7:4] == ISRV[7:4], the manual allows either 0 or TPR[3:0] for PPR[3:0]. 1192*bb4ee6a4SAndroid Build Coastguard Worker assert!( 1193*bb4ee6a4SAndroid Build Coastguard Worker prio == 0 || prio == 0xF, 1194*bb4ee6a4SAndroid Build Coastguard Worker "Expected priority 0 or 0xF, got {}", 1195*bb4ee6a4SAndroid Build Coastguard Worker prio 1196*bb4ee6a4SAndroid Build Coastguard Worker ); 1197*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::TPR, 0x10); 1198*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0x10); 1199*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::TPR, 0); 1200*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0); 1201*bb4ee6a4SAndroid Build Coastguard Worker 1202*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1203*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1204*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Isr, 0xF); 1205*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0); 1206*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Isr, 0x11); 1207*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0x10); 1208*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Isr, 0x11); 1209*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0); 1210*bb4ee6a4SAndroid Build Coastguard Worker 1211*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1212*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1213*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Isr, 0x25); 1214*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Isr, 0x11); 1215*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::TPR, 0x31); 1216*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0x31); 1217*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::TPR, 0x19); 1218*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_processor_priority(), 0x20); 1219*bb4ee6a4SAndroid Build Coastguard Worker a.clear_vector_bit(VectorReg::Isr, 0x25); 1220*bb4ee6a4SAndroid Build Coastguard Worker let prio = a.get_processor_priority(); 1221*bb4ee6a4SAndroid Build Coastguard Worker assert!( 1222*bb4ee6a4SAndroid Build Coastguard Worker prio == 0x10 || prio == 0x19, 1223*bb4ee6a4SAndroid Build Coastguard Worker "Expected priority 0x10 or 0x19, got {}", 1224*bb4ee6a4SAndroid Build Coastguard Worker prio 1225*bb4ee6a4SAndroid Build Coastguard Worker ); 1226*bb4ee6a4SAndroid Build Coastguard Worker } 1227*bb4ee6a4SAndroid Build Coastguard Worker 1228*bb4ee6a4SAndroid Build Coastguard Worker #[test] accept_irq()1229*bb4ee6a4SAndroid Build Coastguard Worker fn accept_irq() { 1230*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1231*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1232*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.init, false); 1233*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.sipi, None); 1234*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.nmis, 0); 1235*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1236*bb4ee6a4SAndroid Build Coastguard Worker vector: 20, 1237*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1238*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1239*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1240*bb4ee6a4SAndroid Build Coastguard Worker }); 1241*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1242*bb4ee6a4SAndroid Build Coastguard Worker vector: 20, 1243*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1244*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1245*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1246*bb4ee6a4SAndroid Build Coastguard Worker }); 1247*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1248*bb4ee6a4SAndroid Build Coastguard Worker vector: 21, 1249*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1250*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1251*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1252*bb4ee6a4SAndroid Build Coastguard Worker }); 1253*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1254*bb4ee6a4SAndroid Build Coastguard Worker vector: 255, 1255*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Lowest, 1256*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1257*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1258*bb4ee6a4SAndroid Build Coastguard Worker }); 1259*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1260*bb4ee6a4SAndroid Build Coastguard Worker vector: 0, 1261*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Init, 1262*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1263*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1264*bb4ee6a4SAndroid Build Coastguard Worker }); 1265*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1266*bb4ee6a4SAndroid Build Coastguard Worker vector: 7, 1267*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Startup, 1268*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1269*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1270*bb4ee6a4SAndroid Build Coastguard Worker }); 1271*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1272*bb4ee6a4SAndroid Build Coastguard Worker vector: 8, 1273*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Startup, 1274*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1275*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1276*bb4ee6a4SAndroid Build Coastguard Worker }); 1277*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1278*bb4ee6a4SAndroid Build Coastguard Worker vector: 0, 1279*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::NMI, 1280*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1281*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1282*bb4ee6a4SAndroid Build Coastguard Worker }); 1283*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1284*bb4ee6a4SAndroid Build Coastguard Worker vector: 0, 1285*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::NMI, 1286*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1287*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1288*bb4ee6a4SAndroid Build Coastguard Worker }); 1289*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.init, true); 1290*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.sipi, Some(8)); 1291*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.nmis, 2); 1292*bb4ee6a4SAndroid Build Coastguard Worker // IRR should be set for 20, 21, and 255. 1293*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1294*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::IRR), 1295*bb4ee6a4SAndroid Build Coastguard Worker 0b0000_0000_0011_0000_0000_0000_0000_0000 1296*bb4ee6a4SAndroid Build Coastguard Worker ); 1297*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 1 * REG_ALIGN_BYTES), 0); 1298*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 2 * REG_ALIGN_BYTES), 0); 1299*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 3 * REG_ALIGN_BYTES), 0); 1300*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 4 * REG_ALIGN_BYTES), 0); 1301*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 5 * REG_ALIGN_BYTES), 0); 1302*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::IRR + 6 * REG_ALIGN_BYTES), 0); 1303*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1304*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::IRR + 7 * REG_ALIGN_BYTES), 1305*bb4ee6a4SAndroid Build Coastguard Worker 0b1000_0000_0000_0000_0000_0000_0000_0000 1306*bb4ee6a4SAndroid Build Coastguard Worker ); 1307*bb4ee6a4SAndroid Build Coastguard Worker // ISR should be unset. 1308*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR), 0); 1309*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR + 1 * REG_ALIGN_BYTES), 0); 1310*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR + 2 * REG_ALIGN_BYTES), 0); 1311*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR + 3 * REG_ALIGN_BYTES), 0); 1312*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR + 4 * REG_ALIGN_BYTES), 0); 1313*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR + 5 * REG_ALIGN_BYTES), 0); 1314*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR + 6 * REG_ALIGN_BYTES), 0); 1315*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::ISR + 7 * REG_ALIGN_BYTES), 0); 1316*bb4ee6a4SAndroid Build Coastguard Worker // TMR should be set for 20 and 255. 1317*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1318*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::TMR), 1319*bb4ee6a4SAndroid Build Coastguard Worker 0b0000_0000_0001_0000_0000_0000_0000_0000 1320*bb4ee6a4SAndroid Build Coastguard Worker ); 1321*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::TMR + 1 * REG_ALIGN_BYTES), 0); 1322*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::TMR + 2 * REG_ALIGN_BYTES), 0); 1323*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::TMR + 3 * REG_ALIGN_BYTES), 0); 1324*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::TMR + 4 * REG_ALIGN_BYTES), 0); 1325*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::TMR + 5 * REG_ALIGN_BYTES), 0); 1326*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.get_reg(Reg::TMR + 6 * REG_ALIGN_BYTES), 0); 1327*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1328*bb4ee6a4SAndroid Build Coastguard Worker a.get_reg(Reg::TMR + 7 * REG_ALIGN_BYTES), 1329*bb4ee6a4SAndroid Build Coastguard Worker 0b1000_0000_0000_0000_0000_0000_0000_0000 1330*bb4ee6a4SAndroid Build Coastguard Worker ); 1331*bb4ee6a4SAndroid Build Coastguard Worker } 1332*bb4ee6a4SAndroid Build Coastguard Worker 1333*bb4ee6a4SAndroid Build Coastguard Worker #[test] icr_write_sends_ipi()1334*bb4ee6a4SAndroid Build Coastguard Worker fn icr_write_sends_ipi() { 1335*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1336*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(229, timer); 1337*bb4ee6a4SAndroid Build Coastguard Worker 1338*bb4ee6a4SAndroid Build Coastguard Worker // Top 8 bits of ICR high are the destination. 1339*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::INTERRUPT_COMMAND_HI as u64, &[0, 0, 0, 42]); 1340*bb4ee6a4SAndroid Build Coastguard Worker #[rustfmt::skip] 1341*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write( 1342*bb4ee6a4SAndroid Build Coastguard Worker Reg::INTERRUPT_COMMAND_LO as u64, 1343*bb4ee6a4SAndroid Build Coastguard Worker &[ 1344*bb4ee6a4SAndroid Build Coastguard Worker 123, // vector 1345*bb4ee6a4SAndroid Build Coastguard Worker 0b11001001, // level 1, assert 1, reserved 0, idle 0, logical 1, lowest priority 001 1346*bb4ee6a4SAndroid Build Coastguard Worker 0b00001100, // reserved 0000, all excluding self 11, reserved 00 1347*bb4ee6a4SAndroid Build Coastguard Worker 0, // reserved 1348*bb4ee6a4SAndroid Build Coastguard Worker ], 1349*bb4ee6a4SAndroid Build Coastguard Worker ); 1350*bb4ee6a4SAndroid Build Coastguard Worker let msg = msg.unwrap(); 1351*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1352*bb4ee6a4SAndroid Build Coastguard Worker msg, 1353*bb4ee6a4SAndroid Build Coastguard Worker ApicBusMsg::Ipi(Interrupt { 1354*bb4ee6a4SAndroid Build Coastguard Worker dest: InterruptDestination { 1355*bb4ee6a4SAndroid Build Coastguard Worker source_id: 229, 1356*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 42, 1357*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::AllExcludingSelf, 1358*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Logical, 1359*bb4ee6a4SAndroid Build Coastguard Worker }, 1360*bb4ee6a4SAndroid Build Coastguard Worker data: InterruptData { 1361*bb4ee6a4SAndroid Build Coastguard Worker vector: 123, 1362*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Lowest, 1363*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1364*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1365*bb4ee6a4SAndroid Build Coastguard Worker }, 1366*bb4ee6a4SAndroid Build Coastguard Worker }) 1367*bb4ee6a4SAndroid Build Coastguard Worker ); 1368*bb4ee6a4SAndroid Build Coastguard Worker 1369*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::INTERRUPT_COMMAND_HI as u64, &[0, 0, 0, 161]); 1370*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write( 1371*bb4ee6a4SAndroid Build Coastguard Worker Reg::INTERRUPT_COMMAND_LO as u64, 1372*bb4ee6a4SAndroid Build Coastguard Worker &[ 1373*bb4ee6a4SAndroid Build Coastguard Worker 255, // vector 1374*bb4ee6a4SAndroid Build Coastguard Worker 0b00010110, // edge 0, deassert 0, reserved 0, pending 1, physical 0, sipi 110 1375*bb4ee6a4SAndroid Build Coastguard Worker 0b00000000, // reserved 0000, no shorthand 00, reserved 00 1376*bb4ee6a4SAndroid Build Coastguard Worker 0, // reserved 1377*bb4ee6a4SAndroid Build Coastguard Worker ], 1378*bb4ee6a4SAndroid Build Coastguard Worker ); 1379*bb4ee6a4SAndroid Build Coastguard Worker let msg = msg.unwrap(); 1380*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1381*bb4ee6a4SAndroid Build Coastguard Worker msg, 1382*bb4ee6a4SAndroid Build Coastguard Worker ApicBusMsg::Ipi(Interrupt { 1383*bb4ee6a4SAndroid Build Coastguard Worker dest: InterruptDestination { 1384*bb4ee6a4SAndroid Build Coastguard Worker source_id: 229, 1385*bb4ee6a4SAndroid Build Coastguard Worker dest_id: 161, 1386*bb4ee6a4SAndroid Build Coastguard Worker shorthand: DestinationShorthand::None, 1387*bb4ee6a4SAndroid Build Coastguard Worker mode: DestinationMode::Physical, 1388*bb4ee6a4SAndroid Build Coastguard Worker }, 1389*bb4ee6a4SAndroid Build Coastguard Worker data: InterruptData { 1390*bb4ee6a4SAndroid Build Coastguard Worker vector: 255, 1391*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Startup, 1392*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1393*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Deassert, 1394*bb4ee6a4SAndroid Build Coastguard Worker }, 1395*bb4ee6a4SAndroid Build Coastguard Worker }) 1396*bb4ee6a4SAndroid Build Coastguard Worker ); 1397*bb4ee6a4SAndroid Build Coastguard Worker } 1398*bb4ee6a4SAndroid Build Coastguard Worker 1399*bb4ee6a4SAndroid Build Coastguard Worker #[test] end_of_interrupt()1400*bb4ee6a4SAndroid Build Coastguard Worker fn end_of_interrupt() { 1401*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1402*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1403*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write(Reg::EOI as u64, &[0; 4]); 1404*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(msg, None); // Spurious EOIs (no interrupt being serviced) should be ignored. 1405*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Isr, 39); 1406*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Isr, 255); 1407*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write(Reg::EOI as u64, &[0; 4]).unwrap(); 1408*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(msg, ApicBusMsg::Eoi(255)); 1409*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(39)); 1410*bb4ee6a4SAndroid Build Coastguard Worker a.set_vector_bit(VectorReg::Isr, 40); 1411*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write(Reg::EOI as u64, &[0; 4]).unwrap(); 1412*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(msg, ApicBusMsg::Eoi(40)); 1413*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(39)); 1414*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write(Reg::EOI as u64, &[0; 4]).unwrap(); 1415*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(msg, ApicBusMsg::Eoi(39)); 1416*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), None); 1417*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write(Reg::EOI as u64, &[0; 4]); 1418*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(msg, None); 1419*bb4ee6a4SAndroid Build Coastguard Worker } 1420*bb4ee6a4SAndroid Build Coastguard Worker 1421*bb4ee6a4SAndroid Build Coastguard Worker #[test] non_fixed_irqs_injected()1422*bb4ee6a4SAndroid Build Coastguard Worker fn non_fixed_irqs_injected() { 1423*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1424*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1425*bb4ee6a4SAndroid Build Coastguard Worker a.set_enabled(true); 1426*bb4ee6a4SAndroid Build Coastguard Worker 1427*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1428*bb4ee6a4SAndroid Build Coastguard Worker vector: 0, 1429*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Init, 1430*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1431*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1432*bb4ee6a4SAndroid Build Coastguard Worker }); 1433*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1434*bb4ee6a4SAndroid Build Coastguard Worker vector: 7, 1435*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Startup, 1436*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1437*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1438*bb4ee6a4SAndroid Build Coastguard Worker }); 1439*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1440*bb4ee6a4SAndroid Build Coastguard Worker vector: 0, 1441*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::NMI, 1442*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1443*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1444*bb4ee6a4SAndroid Build Coastguard Worker }); 1445*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1446*bb4ee6a4SAndroid Build Coastguard Worker vector: 0, 1447*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::NMI, 1448*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1449*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1450*bb4ee6a4SAndroid Build Coastguard Worker }); 1451*bb4ee6a4SAndroid Build Coastguard Worker // Non-fixed irqs should be injected even if vcpu_ready is false. */ 1452*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ false); 1453*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1454*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1455*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1456*bb4ee6a4SAndroid Build Coastguard Worker fixed: None, 1457*bb4ee6a4SAndroid Build Coastguard Worker nmis: 2, 1458*bb4ee6a4SAndroid Build Coastguard Worker init: true, 1459*bb4ee6a4SAndroid Build Coastguard Worker startup: Some(7), 1460*bb4ee6a4SAndroid Build Coastguard Worker needs_window: false, 1461*bb4ee6a4SAndroid Build Coastguard Worker } 1462*bb4ee6a4SAndroid Build Coastguard Worker ); 1463*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.nmis, 0); 1464*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.init, false); 1465*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.sipi, None); 1466*bb4ee6a4SAndroid Build Coastguard Worker 1467*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1468*bb4ee6a4SAndroid Build Coastguard Worker vector: 0, 1469*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::NMI, 1470*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Edge, 1471*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1472*bb4ee6a4SAndroid Build Coastguard Worker }); 1473*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1474*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1475*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1476*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1477*bb4ee6a4SAndroid Build Coastguard Worker nmis: 1, 1478*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1479*bb4ee6a4SAndroid Build Coastguard Worker } 1480*bb4ee6a4SAndroid Build Coastguard Worker ); 1481*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.nmis, 0); 1482*bb4ee6a4SAndroid Build Coastguard Worker 1483*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1484*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1485*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1486*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1487*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1488*bb4ee6a4SAndroid Build Coastguard Worker } 1489*bb4ee6a4SAndroid Build Coastguard Worker ); 1490*bb4ee6a4SAndroid Build Coastguard Worker } 1491*bb4ee6a4SAndroid Build Coastguard Worker 1492*bb4ee6a4SAndroid Build Coastguard Worker #[test] fixed_irq_injected()1493*bb4ee6a4SAndroid Build Coastguard Worker fn fixed_irq_injected() { 1494*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1495*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1496*bb4ee6a4SAndroid Build Coastguard Worker a.set_enabled(true); 1497*bb4ee6a4SAndroid Build Coastguard Worker 1498*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1499*bb4ee6a4SAndroid Build Coastguard Worker vector: 0x10, 1500*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1501*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1502*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1503*bb4ee6a4SAndroid Build Coastguard Worker }); 1504*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ false); 1505*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1506*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1507*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1508*bb4ee6a4SAndroid Build Coastguard Worker fixed: None, 1509*bb4ee6a4SAndroid Build Coastguard Worker needs_window: true, 1510*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1511*bb4ee6a4SAndroid Build Coastguard Worker } 1512*bb4ee6a4SAndroid Build Coastguard Worker ); 1513*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0x10)); 1514*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), None); 1515*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1516*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1517*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1518*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1519*bb4ee6a4SAndroid Build Coastguard Worker fixed: Some(0x10), 1520*bb4ee6a4SAndroid Build Coastguard Worker needs_window: false, 1521*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1522*bb4ee6a4SAndroid Build Coastguard Worker } 1523*bb4ee6a4SAndroid Build Coastguard Worker ); 1524*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), None); 1525*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(0x10)); 1526*bb4ee6a4SAndroid Build Coastguard Worker } 1527*bb4ee6a4SAndroid Build Coastguard Worker 1528*bb4ee6a4SAndroid Build Coastguard Worker #[test] high_priority_irq_injected()1529*bb4ee6a4SAndroid Build Coastguard Worker fn high_priority_irq_injected() { 1530*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1531*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1532*bb4ee6a4SAndroid Build Coastguard Worker a.set_enabled(true); 1533*bb4ee6a4SAndroid Build Coastguard Worker 1534*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1535*bb4ee6a4SAndroid Build Coastguard Worker vector: 0x10, 1536*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1537*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1538*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1539*bb4ee6a4SAndroid Build Coastguard Worker }); 1540*bb4ee6a4SAndroid Build Coastguard Worker let _ = a.get_pending_irqs(/* vcpu_ready= */ true); 1541*bb4ee6a4SAndroid Build Coastguard Worker 1542*bb4ee6a4SAndroid Build Coastguard Worker // An interrupt in a higher priority class should be injected immediately if the window is 1543*bb4ee6a4SAndroid Build Coastguard Worker // open. 1544*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1545*bb4ee6a4SAndroid Build Coastguard Worker vector: 0x20, 1546*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1547*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1548*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1549*bb4ee6a4SAndroid Build Coastguard Worker }); 1550*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ false); 1551*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1552*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1553*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1554*bb4ee6a4SAndroid Build Coastguard Worker fixed: None, 1555*bb4ee6a4SAndroid Build Coastguard Worker needs_window: true, 1556*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1557*bb4ee6a4SAndroid Build Coastguard Worker } 1558*bb4ee6a4SAndroid Build Coastguard Worker ); 1559*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0x20)); 1560*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(0x10)); 1561*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1562*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1563*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1564*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1565*bb4ee6a4SAndroid Build Coastguard Worker fixed: Some(0x20), 1566*bb4ee6a4SAndroid Build Coastguard Worker needs_window: false, 1567*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1568*bb4ee6a4SAndroid Build Coastguard Worker } 1569*bb4ee6a4SAndroid Build Coastguard Worker ); 1570*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), None); 1571*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(0x20)); 1572*bb4ee6a4SAndroid Build Coastguard Worker } 1573*bb4ee6a4SAndroid Build Coastguard Worker 1574*bb4ee6a4SAndroid Build Coastguard Worker #[test] low_priority_irq_deferred()1575*bb4ee6a4SAndroid Build Coastguard Worker fn low_priority_irq_deferred() { 1576*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1577*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1578*bb4ee6a4SAndroid Build Coastguard Worker a.set_enabled(true); 1579*bb4ee6a4SAndroid Build Coastguard Worker 1580*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1581*bb4ee6a4SAndroid Build Coastguard Worker vector: 0x10, 1582*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1583*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1584*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1585*bb4ee6a4SAndroid Build Coastguard Worker }); 1586*bb4ee6a4SAndroid Build Coastguard Worker let _ = a.get_pending_irqs(/* vcpu_ready= */ true); 1587*bb4ee6a4SAndroid Build Coastguard Worker 1588*bb4ee6a4SAndroid Build Coastguard Worker // An interrupt in the same or lower priority class should be deferred. 1589*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1590*bb4ee6a4SAndroid Build Coastguard Worker vector: 0x15, 1591*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1592*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1593*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1594*bb4ee6a4SAndroid Build Coastguard Worker }); 1595*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1596*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1597*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1598*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1599*bb4ee6a4SAndroid Build Coastguard Worker fixed: None, 1600*bb4ee6a4SAndroid Build Coastguard Worker // Not injectable due to higher priority ISRV, so no window needed. 1601*bb4ee6a4SAndroid Build Coastguard Worker needs_window: false, 1602*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1603*bb4ee6a4SAndroid Build Coastguard Worker } 1604*bb4ee6a4SAndroid Build Coastguard Worker ); 1605*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(0x15)); 1606*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Isr), Some(0x10)); 1607*bb4ee6a4SAndroid Build Coastguard Worker 1608*bb4ee6a4SAndroid Build Coastguard Worker // EOI lets it be injected. 1609*bb4ee6a4SAndroid Build Coastguard Worker let msg = a.write(Reg::EOI as u64, &[0; 4]).unwrap(); 1610*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(msg, ApicBusMsg::Eoi(0x10)); 1611*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1612*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1613*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1614*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1615*bb4ee6a4SAndroid Build Coastguard Worker fixed: Some(0x15), 1616*bb4ee6a4SAndroid Build Coastguard Worker needs_window: false, 1617*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1618*bb4ee6a4SAndroid Build Coastguard Worker } 1619*bb4ee6a4SAndroid Build Coastguard Worker ); 1620*bb4ee6a4SAndroid Build Coastguard Worker } 1621*bb4ee6a4SAndroid Build Coastguard Worker 1622*bb4ee6a4SAndroid Build Coastguard Worker #[test] tpr_defers_injection()1623*bb4ee6a4SAndroid Build Coastguard Worker fn tpr_defers_injection() { 1624*bb4ee6a4SAndroid Build Coastguard Worker let timer = Box::new(FakeTimer::new(Arc::new(Mutex::new(FakeClock::new())))); 1625*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, timer); 1626*bb4ee6a4SAndroid Build Coastguard Worker a.set_enabled(true); 1627*bb4ee6a4SAndroid Build Coastguard Worker 1628*bb4ee6a4SAndroid Build Coastguard Worker a.accept_irq(&InterruptData { 1629*bb4ee6a4SAndroid Build Coastguard Worker vector: 0x25, 1630*bb4ee6a4SAndroid Build Coastguard Worker delivery: DeliveryMode::Fixed, 1631*bb4ee6a4SAndroid Build Coastguard Worker trigger: TriggerMode::Level, 1632*bb4ee6a4SAndroid Build Coastguard Worker level: Level::Assert, 1633*bb4ee6a4SAndroid Build Coastguard Worker }); 1634*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::TPR, 0x20); 1635*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1636*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1637*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1638*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1639*bb4ee6a4SAndroid Build Coastguard Worker fixed: None, 1640*bb4ee6a4SAndroid Build Coastguard Worker needs_window: false, 1641*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1642*bb4ee6a4SAndroid Build Coastguard Worker } 1643*bb4ee6a4SAndroid Build Coastguard Worker ); 1644*bb4ee6a4SAndroid Build Coastguard Worker a.set_reg(Reg::TPR, 0x19); 1645*bb4ee6a4SAndroid Build Coastguard Worker let irqs = a.get_pending_irqs(/* vcpu_ready= */ true); 1646*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!( 1647*bb4ee6a4SAndroid Build Coastguard Worker irqs, 1648*bb4ee6a4SAndroid Build Coastguard Worker PendingInterrupts { 1649*bb4ee6a4SAndroid Build Coastguard Worker fixed: Some(0x25), 1650*bb4ee6a4SAndroid Build Coastguard Worker needs_window: false, 1651*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default() 1652*bb4ee6a4SAndroid Build Coastguard Worker } 1653*bb4ee6a4SAndroid Build Coastguard Worker ); 1654*bb4ee6a4SAndroid Build Coastguard Worker } 1655*bb4ee6a4SAndroid Build Coastguard Worker 1656*bb4ee6a4SAndroid Build Coastguard Worker #[test] timer_starts()1657*bb4ee6a4SAndroid Build Coastguard Worker fn timer_starts() { 1658*bb4ee6a4SAndroid Build Coastguard Worker let clock = Arc::new(Mutex::new(FakeClock::new())); 1659*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, Box::new(FakeTimer::new(clock.clone()))); 1660*bb4ee6a4SAndroid Build Coastguard Worker a.set_enabled(true); 1661*bb4ee6a4SAndroid Build Coastguard Worker 1662*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::LOCAL_TIMER as u64, &TIMER_MODE_ONE_SHOT.to_le_bytes()); 1663*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::TIMER_DIVIDE_CONTROL as u64, &[1, 0, 0, 0]); // Frequency divided by 4. 1664*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::TIMER_INITIAL_COUNT as u64, &500_000_u32.to_le_bytes()); 1665*bb4ee6a4SAndroid Build Coastguard Worker 1666*bb4ee6a4SAndroid Build Coastguard Worker let timer_ns = u64::try_from(4 * 500_000 * a.get_cycle_length().as_nanos()).unwrap(); 1667*bb4ee6a4SAndroid Build Coastguard Worker clock.lock().add_ns(timer_ns - 1); 1668*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.timer.mark_waited(), Ok(true)); 1669*bb4ee6a4SAndroid Build Coastguard Worker clock.lock().add_ns(1); 1670*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.timer.mark_waited(), Ok(false)); 1671*bb4ee6a4SAndroid Build Coastguard Worker // One-shot timer shouldn't fire again. 1672*bb4ee6a4SAndroid Build Coastguard Worker clock.lock().add_ns(timer_ns); 1673*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.timer.mark_waited(), Ok(true)); 1674*bb4ee6a4SAndroid Build Coastguard Worker 1675*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::TIMER_DIVIDE_CONTROL as u64, &[0b1011, 0, 0, 0]); // Frequency divided by 1. 1676*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::LOCAL_TIMER as u64, &TIMER_MODE_PERIODIC.to_le_bytes()); 1677*bb4ee6a4SAndroid Build Coastguard Worker a.write( 1678*bb4ee6a4SAndroid Build Coastguard Worker Reg::TIMER_INITIAL_COUNT as u64, 1679*bb4ee6a4SAndroid Build Coastguard Worker &1_000_000_u32.to_le_bytes(), 1680*bb4ee6a4SAndroid Build Coastguard Worker ); 1681*bb4ee6a4SAndroid Build Coastguard Worker 1682*bb4ee6a4SAndroid Build Coastguard Worker let timer_ns = u64::try_from(1 * 1_000_000 * a.get_cycle_length().as_nanos()).unwrap(); 1683*bb4ee6a4SAndroid Build Coastguard Worker clock.lock().add_ns(timer_ns - 1); 1684*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.timer.mark_waited(), Ok(true)); 1685*bb4ee6a4SAndroid Build Coastguard Worker clock.lock().add_ns(1); 1686*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.timer.mark_waited(), Ok(false)); 1687*bb4ee6a4SAndroid Build Coastguard Worker clock.lock().add_ns(timer_ns - 1); 1688*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.timer.mark_waited(), Ok(true)); 1689*bb4ee6a4SAndroid Build Coastguard Worker clock.lock().add_ns(1); 1690*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.timer.mark_waited(), Ok(false)); 1691*bb4ee6a4SAndroid Build Coastguard Worker } 1692*bb4ee6a4SAndroid Build Coastguard Worker 1693*bb4ee6a4SAndroid Build Coastguard Worker #[test] timer_interrupts()1694*bb4ee6a4SAndroid Build Coastguard Worker fn timer_interrupts() { 1695*bb4ee6a4SAndroid Build Coastguard Worker let clock = Arc::new(Mutex::new(FakeClock::new())); 1696*bb4ee6a4SAndroid Build Coastguard Worker let mut a = Apic::new(0, Box::new(FakeTimer::new(clock.clone()))); 1697*bb4ee6a4SAndroid Build Coastguard Worker a.set_enabled(true); 1698*bb4ee6a4SAndroid Build Coastguard Worker 1699*bb4ee6a4SAndroid Build Coastguard Worker // Masked timer shouldn't interrupt. 1700*bb4ee6a4SAndroid Build Coastguard Worker let val = TIMER_MODE_PERIODIC | LOCAL_VECTOR_MASKED | 123; 1701*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::LOCAL_TIMER as u64, &val.to_le_bytes()); 1702*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::TIMER_DIVIDE_CONTROL as u64, &[0b1011, 0, 0, 0]); // Frequency divided by 1. 1703*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::TIMER_INITIAL_COUNT as u64, &500_000_u32.to_le_bytes()); 1704*bb4ee6a4SAndroid Build Coastguard Worker clock 1705*bb4ee6a4SAndroid Build Coastguard Worker .lock() 1706*bb4ee6a4SAndroid Build Coastguard Worker .add_ns(500_000 * a.get_cycle_length().as_nanos() as u64); 1707*bb4ee6a4SAndroid Build Coastguard Worker a.handle_timer_expiration(); 1708*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), None); 1709*bb4ee6a4SAndroid Build Coastguard Worker 1710*bb4ee6a4SAndroid Build Coastguard Worker // Unmasked timer should interrupt on the vector in LOCAL_TIMER & 0xFF. 1711*bb4ee6a4SAndroid Build Coastguard Worker let val = TIMER_MODE_PERIODIC | 123; 1712*bb4ee6a4SAndroid Build Coastguard Worker a.write(Reg::LOCAL_TIMER as u64, &val.to_le_bytes()); 1713*bb4ee6a4SAndroid Build Coastguard Worker clock 1714*bb4ee6a4SAndroid Build Coastguard Worker .lock() 1715*bb4ee6a4SAndroid Build Coastguard Worker .add_ns(500_000 * a.get_cycle_length().as_nanos() as u64); 1716*bb4ee6a4SAndroid Build Coastguard Worker a.handle_timer_expiration(); 1717*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(a.highest_bit_in_vector(VectorReg::Irr), Some(123)); 1718*bb4ee6a4SAndroid Build Coastguard Worker } 1719*bb4ee6a4SAndroid Build Coastguard Worker } 1720