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