• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use base::Result;
6 use hypervisor::{IoapicState, LapicState, PicSelect, PicState, PitState};
7 
8 use crate::IrqChip;
9 
10 pub trait IrqChipX86_64: IrqChip {
11     // Clones this trait as a `Box` version of itself.
try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>12     fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>;
13 
14     // Get this as the super-trait IrqChip.
as_irq_chip(&self) -> &dyn IrqChip15     fn as_irq_chip(&self) -> &dyn IrqChip;
16 
17     // Get this as the mutable super-trait IrqChip.
as_irq_chip_mut(&mut self) -> &mut dyn IrqChip18     fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip;
19 
20     /// Get the current state of the PIC
get_pic_state(&self, select: PicSelect) -> Result<PicState>21     fn get_pic_state(&self, select: PicSelect) -> Result<PicState>;
22 
23     /// Set the current state of the PIC
set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>24     fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>;
25 
26     /// Get the current state of the IOAPIC
get_ioapic_state(&self) -> Result<IoapicState>27     fn get_ioapic_state(&self) -> Result<IoapicState>;
28 
29     /// Set the current state of the IOAPIC
set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>30     fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>;
31 
32     /// Get the current state of the specified VCPU's local APIC
get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>33     fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>;
34 
35     /// Set the current state of the specified VCPU's local APIC
set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>36     fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>;
37 
38     /// Retrieves the state of the PIT.
get_pit(&self) -> Result<PitState>39     fn get_pit(&self) -> Result<PitState>;
40 
41     /// Sets the state of the PIT.
set_pit(&mut self, state: &PitState) -> Result<()>42     fn set_pit(&mut self, state: &PitState) -> Result<()>;
43 
44     /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused.
pit_uses_speaker_port(&self) -> bool45     fn pit_uses_speaker_port(&self) -> bool;
46 }
47 
48 #[cfg(test)]
49 /// This module contains tests that apply to any implementations of IrqChipX86_64
50 pub(super) mod tests {
51     use super::*;
52     use hypervisor::{IrqRoute, IrqSource, IrqSourceChip};
53 
test_get_pic(mut chip: impl IrqChipX86_64)54     pub fn test_get_pic(mut chip: impl IrqChipX86_64) {
55         let state = chip
56             .get_pic_state(PicSelect::Primary)
57             .expect("could not get pic state");
58 
59         // Default is that no irq lines are asserted
60         assert_eq!(state.irr, 0);
61 
62         // Assert Irq Line 0
63         chip.service_irq(0, true).expect("could not service irq");
64 
65         let state = chip
66             .get_pic_state(PicSelect::Primary)
67             .expect("could not get pic state");
68 
69         // Bit 0 should now be 1
70         assert_eq!(state.irr, 1);
71     }
72 
test_set_pic(mut chip: impl IrqChipX86_64)73     pub fn test_set_pic(mut chip: impl IrqChipX86_64) {
74         let mut state = chip
75             .get_pic_state(PicSelect::Primary)
76             .expect("could not get pic state");
77 
78         // set bits 0 and 1
79         state.irr = 3;
80 
81         chip.set_pic_state(PicSelect::Primary, &state)
82             .expect("could not set the pic state");
83 
84         let state = chip
85             .get_pic_state(PicSelect::Primary)
86             .expect("could not get pic state");
87 
88         // Bits 1 and 0 should now be 1
89         assert_eq!(state.irr, 3);
90     }
91 
test_get_ioapic(mut chip: impl IrqChipX86_64)92     pub fn test_get_ioapic(mut chip: impl IrqChipX86_64) {
93         let state = chip.get_ioapic_state().expect("could not get ioapic state");
94 
95         // Default is that no irq lines are asserted
96         assert_eq!(state.current_interrupt_level_bitmap, 0);
97 
98         // Default routing entries has routes 0..24 routed to vectors 0..24
99         for i in 0..24 {
100             // when the ioapic is reset by kvm, it defaults to all zeroes except the
101             // interrupt mask is set to 1, which is bit 16
102             assert_eq!(state.redirect_table[i].get(0, 64), 1 << 16);
103         }
104 
105         // Assert Irq Line 1
106         chip.service_irq(1, true).expect("could not set irq line");
107 
108         let state = chip.get_ioapic_state().expect("could not get ioapic state");
109 
110         // Bit 1 should now be 1
111         assert_eq!(state.current_interrupt_level_bitmap, 2);
112     }
113 
test_set_ioapic(mut chip: impl IrqChipX86_64)114     pub fn test_set_ioapic(mut chip: impl IrqChipX86_64) {
115         let mut state = chip.get_ioapic_state().expect("could not get ioapic state");
116 
117         // set a vector in the redirect table
118         state.redirect_table[2].set_vector(15);
119         // set the irq line status on that entry
120         state.current_interrupt_level_bitmap = 4;
121 
122         chip.set_ioapic_state(&state)
123             .expect("could not set the ioapic state");
124 
125         let state = chip.get_ioapic_state().expect("could not get ioapic state");
126 
127         // verify that get_ioapic_state returns what we set
128         assert_eq!(state.redirect_table[2].get_vector(), 15);
129         assert_eq!(state.current_interrupt_level_bitmap, 4);
130     }
131 
test_get_pit(chip: impl IrqChipX86_64)132     pub fn test_get_pit(chip: impl IrqChipX86_64) {
133         let state = chip.get_pit().expect("failed to get pit state");
134 
135         assert_eq!(state.flags, 0);
136         // assert reset state of pit
137         for i in 0..3 {
138             // initial count of 0 sets it to 0x10000;
139             assert_eq!(state.channels[i].count, 0x10000);
140         }
141     }
142 
test_set_pit(mut chip: impl IrqChipX86_64)143     pub fn test_set_pit(mut chip: impl IrqChipX86_64) {
144         let mut state = chip.get_pit().expect("failed to get pit state");
145 
146         // set some values
147         state.channels[0].count = 500;
148         state.channels[0].mode = 1;
149 
150         // Setting the pit should initialize the one-shot timer
151         chip.set_pit(&state).expect("failed to set pit state");
152 
153         let state = chip.get_pit().expect("failed to get pit state");
154 
155         // check the values we set
156         assert_eq!(state.channels[0].count, 500);
157         assert_eq!(state.channels[0].mode, 1);
158     }
159 
test_get_lapic(chip: impl IrqChipX86_64)160     pub fn test_get_lapic(chip: impl IrqChipX86_64) {
161         let state = chip.get_lapic_state(0).expect("failed to get lapic state");
162 
163         // Checking some APIC reg defaults for KVM:
164         // DFR default is 0xffffffff
165         assert_eq!(state.regs[0xe], 0xffffffff);
166         // SPIV default is 0xff
167         assert_eq!(state.regs[0xf], 0xff);
168     }
169 
test_set_lapic(mut chip: impl IrqChipX86_64)170     pub fn test_set_lapic(mut chip: impl IrqChipX86_64) {
171         // Get default state
172         let mut state = chip.get_lapic_state(0).expect("failed to get lapic state");
173 
174         // ESR should start out as 0
175         assert_eq!(state.regs[8], 0);
176         // Set a value in the ESR
177         state.regs[8] = 1 << 8;
178         chip.set_lapic_state(0, &state)
179             .expect("failed to set lapic state");
180 
181         // check that new ESR value stuck
182         let state = chip.get_lapic_state(0).expect("failed to get lapic state");
183         assert_eq!(state.regs[8], 1 << 8);
184     }
185 
186     /// Helper function for checking the pic interrupt status
check_pic_interrupts(chip: &impl IrqChipX86_64, select: PicSelect, value: u8)187     fn check_pic_interrupts(chip: &impl IrqChipX86_64, select: PicSelect, value: u8) {
188         let state = chip
189             .get_pic_state(select)
190             .expect("could not get ioapic state");
191 
192         assert_eq!(state.irr, value);
193     }
194 
195     /// Helper function for checking the ioapic interrupt status
check_ioapic_interrupts(chip: &impl IrqChipX86_64, value: u32)196     fn check_ioapic_interrupts(chip: &impl IrqChipX86_64, value: u32) {
197         let state = chip.get_ioapic_state().expect("could not get ioapic state");
198 
199         // since the irq route goes nowhere the bitmap should still be 0
200         assert_eq!(state.current_interrupt_level_bitmap, value);
201     }
202 
test_route_irq(mut chip: impl IrqChipX86_64)203     pub fn test_route_irq(mut chip: impl IrqChipX86_64) {
204         // clear out irq routes
205         chip.set_irq_routes(&[])
206             .expect("failed to set empty irq routes");
207         // assert Irq Line 1
208         chip.service_irq(1, true).expect("could not set irq line");
209 
210         // no pic or ioapic interrupts should be asserted
211         check_pic_interrupts(&chip, PicSelect::Primary, 0);
212         check_ioapic_interrupts(&chip, 0);
213 
214         // now we route gsi 1 to pin 3 of the ioapic and pin 6 of the primary pic
215         chip.route_irq(IrqRoute {
216             gsi: 1,
217             source: IrqSource::Irqchip {
218                 chip: IrqSourceChip::Ioapic,
219                 pin: 3,
220             },
221         })
222         .expect("failed to assert irq route");
223         // re-assert Irq Line 1
224         chip.service_irq(1, true).expect("could not set irq line");
225 
226         // no pic line should be asserted, ioapic pin 3 should be asserted
227         check_pic_interrupts(&chip, PicSelect::Primary, 0);
228         check_ioapic_interrupts(&chip, 1 << 3);
229 
230         // de-assert Irq Line 1
231         chip.service_irq(1, false).expect("could not set irq line");
232 
233         // no pic or ioapic interrupts should be asserted
234         check_pic_interrupts(&chip, PicSelect::Primary, 0);
235         check_ioapic_interrupts(&chip, 0);
236 
237         // add pic route
238         chip.route_irq(IrqRoute {
239             gsi: 2,
240             source: IrqSource::Irqchip {
241                 chip: IrqSourceChip::PicPrimary,
242                 pin: 6,
243             },
244         })
245         .expect("failed to route irq");
246 
247         // re-assert Irq Line 1, it should still affect only the ioapic
248         chip.service_irq(1, true).expect("could not set irq line");
249 
250         // no pic line should be asserted, ioapic pin 3 should be asserted
251         check_pic_interrupts(&chip, PicSelect::Primary, 0);
252         check_ioapic_interrupts(&chip, 1 << 3);
253 
254         // assert Irq Line 2
255         chip.service_irq(2, true).expect("could not set irq line");
256 
257         // pic pin 6 should be asserted, ioapic pin 3 should be asserted
258         check_pic_interrupts(&chip, PicSelect::Primary, 1 << 6);
259         check_ioapic_interrupts(&chip, 1 << 3);
260     }
261 }
262