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