xref: /aosp_15_r20/external/crosvm/devices/src/irqchip/apic.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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