xref: /aosp_15_r20/external/crosvm/devices/tests/irqchip/x86_64.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #![cfg(target_arch = "x86_64")]
6 
7 use devices::IrqChipX86_64;
8 use devices::Routes;
9 use hypervisor::IrqRoute;
10 use hypervisor::IrqSource;
11 use hypervisor::IrqSourceChip;
12 use hypervisor::PicSelect;
13 
14 #[allow(unused)]
test_get_pic(mut chip: impl IrqChipX86_64)15 pub fn test_get_pic(mut chip: impl IrqChipX86_64) {
16     let state = chip
17         .get_pic_state(PicSelect::Primary)
18         .expect("could not get pic state");
19 
20     // Default is that no irq lines are asserted
21     assert_eq!(state.irr, 0);
22 
23     // Assert Irq Line 0
24     chip.service_irq(0, true).expect("could not service irq");
25 
26     let state = chip
27         .get_pic_state(PicSelect::Primary)
28         .expect("could not get pic state");
29 
30     // Bit 0 should now be 1
31     assert_eq!(state.irr, 1);
32 }
33 
test_set_pic(mut chip: impl IrqChipX86_64)34 pub fn test_set_pic(mut chip: impl IrqChipX86_64) {
35     let mut state = chip
36         .get_pic_state(PicSelect::Primary)
37         .expect("could not get pic state");
38 
39     // set bits 0 and 1
40     state.irr = 3;
41 
42     chip.set_pic_state(PicSelect::Primary, &state)
43         .expect("could not set the pic state");
44 
45     let state = chip
46         .get_pic_state(PicSelect::Primary)
47         .expect("could not get pic state");
48 
49     // Bits 1 and 0 should now be 1
50     assert_eq!(state.irr, 3);
51 }
52 
test_get_ioapic(mut chip: impl IrqChipX86_64)53 pub fn test_get_ioapic(mut chip: impl IrqChipX86_64) {
54     let state = chip.get_ioapic_state().expect("could not get ioapic state");
55 
56     // Default is that no irq lines are asserted
57     assert_eq!(state.current_interrupt_level_bitmap, 0);
58 
59     // Default routing entries has routes 0..24 routed to vectors 0..24
60     for i in 0..24 {
61         // when the ioapic is reset by kvm, it defaults to all zeroes except the
62         // interrupt mask is set to 1, which is bit 16
63         assert_eq!(state.redirect_table[i].get(0, 64), 1 << 16);
64     }
65 
66     // Assert Irq Line 1
67     chip.service_irq(1, true).expect("could not set irq line");
68 
69     let state = chip.get_ioapic_state().expect("could not get ioapic state");
70 
71     // Bit 1 should now be 1
72     assert_eq!(state.current_interrupt_level_bitmap, 2);
73 }
74 
test_set_ioapic(mut chip: impl IrqChipX86_64)75 pub fn test_set_ioapic(mut chip: impl IrqChipX86_64) {
76     let mut state = chip.get_ioapic_state().expect("could not get ioapic state");
77 
78     // set a vector in the redirect table
79     state.redirect_table[2].set_vector(15);
80     // set the irq line status on that entry
81     state.current_interrupt_level_bitmap = 4;
82 
83     chip.set_ioapic_state(&state)
84         .expect("could not set the ioapic state");
85 
86     let state = chip.get_ioapic_state().expect("could not get ioapic state");
87 
88     // verify that get_ioapic_state returns what we set
89     assert_eq!(state.redirect_table[2].get_vector(), 15);
90     assert_eq!(state.current_interrupt_level_bitmap, 4);
91 }
92 
test_get_pit(chip: impl IrqChipX86_64)93 pub fn test_get_pit(chip: impl IrqChipX86_64) {
94     let state = chip.get_pit().expect("failed to get pit state");
95 
96     assert_eq!(state.flags, 0);
97     // assert reset state of pit
98     for i in 0..3 {
99         // initial count of 0 sets it to 0x10000;
100         assert_eq!(state.channels[i].count, 0x10000);
101     }
102 }
103 
test_set_pit(mut chip: impl IrqChipX86_64)104 pub fn test_set_pit(mut chip: impl IrqChipX86_64) {
105     let mut state = chip.get_pit().expect("failed to get pit state");
106 
107     // set some values
108     state.channels[0].count = 500;
109     state.channels[0].mode = 1;
110 
111     // Setting the pit should initialize the one-shot timer
112     chip.set_pit(&state).expect("failed to set pit state");
113 
114     let state = chip.get_pit().expect("failed to get pit state");
115 
116     // check the values we set
117     assert_eq!(state.channels[0].count, 500);
118     assert_eq!(state.channels[0].mode, 1);
119 }
120 
121 #[allow(unused)]
test_get_lapic(chip: impl IrqChipX86_64)122 pub fn test_get_lapic(chip: impl IrqChipX86_64) {
123     let state = chip.get_lapic_state(0).expect("failed to get lapic state");
124 
125     // Checking some APIC reg defaults for KVM:
126     // DFR default is 0xffffffff
127     assert_eq!(state.regs[0xe], 0xffffffff);
128     // SPIV default is 0xff
129     assert_eq!(state.regs[0xf], 0xff);
130 }
131 
132 #[allow(unused)]
test_set_lapic(mut chip: impl IrqChipX86_64)133 pub fn test_set_lapic(mut chip: impl IrqChipX86_64) {
134     // Get default state
135     let mut state = chip.get_lapic_state(0).expect("failed to get lapic state");
136 
137     // ESR should start out as 0
138     assert_eq!(state.regs[8], 0);
139     // Set a value in the ESR
140     state.regs[8] = 1 << 8;
141     chip.set_lapic_state(0, &state)
142         .expect("failed to set lapic state");
143 
144     // check that new ESR value stuck
145     let state = chip.get_lapic_state(0).expect("failed to get lapic state");
146     assert_eq!(state.regs[8], 1 << 8);
147 }
148 
149 /// Helper function for checking the pic interrupt status
check_pic_interrupts(chip: &impl IrqChipX86_64, select: PicSelect, value: u8)150 fn check_pic_interrupts(chip: &impl IrqChipX86_64, select: PicSelect, value: u8) {
151     let state = chip
152         .get_pic_state(select)
153         .expect("could not get ioapic state");
154 
155     assert_eq!(state.irr, value);
156 }
157 
158 /// Helper function for checking the ioapic interrupt status
check_ioapic_interrupts(chip: &impl IrqChipX86_64, value: u32)159 fn check_ioapic_interrupts(chip: &impl IrqChipX86_64, value: u32) {
160     let state = chip.get_ioapic_state().expect("could not get ioapic state");
161 
162     // since the irq route goes nowhere the bitmap should still be 0
163     assert_eq!(state.current_interrupt_level_bitmap, value);
164 }
165 
test_route_irq(mut chip: impl IrqChipX86_64)166 pub fn test_route_irq(mut chip: impl IrqChipX86_64) {
167     // clear out irq routes
168     chip.set_irq_routes(&[])
169         .expect("failed to set empty irq routes");
170     // assert Irq Line 1
171     chip.service_irq(1, true).expect("could not set irq line");
172 
173     // no pic or ioapic interrupts should be asserted
174     check_pic_interrupts(&chip, PicSelect::Primary, 0);
175     check_ioapic_interrupts(&chip, 0);
176 
177     // now we route gsi 1 to pin 3 of the ioapic and pin 6 of the primary pic
178     chip.route_irq(IrqRoute {
179         gsi: 1,
180         source: IrqSource::Irqchip {
181             chip: IrqSourceChip::Ioapic,
182             pin: 3,
183         },
184     })
185     .expect("failed to assert irq route");
186     // re-assert Irq Line 1
187     chip.service_irq(1, true).expect("could not set irq line");
188 
189     // no pic line should be asserted, ioapic pin 3 should be asserted
190     check_pic_interrupts(&chip, PicSelect::Primary, 0);
191     check_ioapic_interrupts(&chip, 1 << 3);
192 
193     // de-assert Irq Line 1
194     chip.service_irq(1, false).expect("could not set irq line");
195 
196     // no pic or ioapic interrupts should be asserted
197     check_pic_interrupts(&chip, PicSelect::Primary, 0);
198     check_ioapic_interrupts(&chip, 0);
199 
200     // add pic route
201     chip.route_irq(IrqRoute {
202         gsi: 2,
203         source: IrqSource::Irqchip {
204             chip: IrqSourceChip::PicPrimary,
205             pin: 6,
206         },
207     })
208     .expect("failed to route irq");
209 
210     // re-assert Irq Line 1, it should still affect only the ioapic
211     chip.service_irq(1, true).expect("could not set irq line");
212 
213     // no pic line should be asserted, ioapic pin 3 should be asserted
214     check_pic_interrupts(&chip, PicSelect::Primary, 0);
215     check_ioapic_interrupts(&chip, 1 << 3);
216 
217     // assert Irq Line 2
218     chip.service_irq(2, true).expect("could not set irq line");
219 
220     // pic pin 6 should be asserted, ioapic pin 3 should be asserted
221     check_pic_interrupts(&chip, PicSelect::Primary, 1 << 6);
222     check_ioapic_interrupts(&chip, 1 << 3);
223 }
224 
225 #[test]
add_routes()226 fn add_routes() {
227     let ioapic_pins = hypervisor::NUM_IOAPIC_PINS;
228     let mut r = Routes::new();
229     r.replace_all(&Routes::default_pic_ioapic_routes(ioapic_pins))
230         .unwrap();
231 
232     assert_eq!(r[0].len(), 2);
233 
234     assert_eq!(r[ioapic_pins - 1].len(), 1);
235     r.add(IrqRoute {
236         gsi: ioapic_pins as u32 - 1,
237         source: IrqSource::Irqchip {
238             chip: IrqSourceChip::Ioapic,
239             pin: 3,
240         },
241     })
242     .unwrap();
243     assert_eq!(r[ioapic_pins - 1].len(), 1);
244     r.add(IrqRoute {
245         gsi: ioapic_pins as u32 - 1,
246         source: IrqSource::Irqchip {
247             chip: IrqSourceChip::PicPrimary,
248             pin: 3,
249         },
250     })
251     .unwrap();
252     assert_eq!(r[ioapic_pins - 1].len(), 2);
253     assert!(r
254         .add(IrqRoute {
255             gsi: ioapic_pins as u32 - 1,
256             source: IrqSource::Msi {
257                 address: 0,
258                 data: 0
259             },
260         })
261         .is_err(),);
262     assert_eq!(r[ioapic_pins - 1].len(), 2);
263 
264     assert_eq!(r[ioapic_pins].len(), 0);
265     r.add(IrqRoute {
266         gsi: ioapic_pins as u32,
267         source: IrqSource::Msi {
268             address: 0,
269             data: 0,
270         },
271     })
272     .unwrap();
273     assert_eq!(r[ioapic_pins].len(), 1);
274     assert!(r
275         .add(IrqRoute {
276             gsi: ioapic_pins as u32,
277             source: IrqSource::Irqchip {
278                 chip: IrqSourceChip::Ioapic,
279                 pin: 3
280             },
281         })
282         .is_err(),);
283     assert_eq!(r[ioapic_pins].len(), 1);
284 
285     assert_eq!(r[500].len(), 0);
286 }
287