xref: /aosp_15_r20/external/crosvm/devices/tests/irqchip/whpx.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 #![cfg(target_arch = "x86_64")]
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use base::EventWaitResult;
8*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
9*bb4ee6a4SAndroid Build Coastguard Worker use devices::Bus;
10*bb4ee6a4SAndroid Build Coastguard Worker use devices::BusType;
11*bb4ee6a4SAndroid Build Coastguard Worker use devices::CrosvmDeviceId;
12*bb4ee6a4SAndroid Build Coastguard Worker use devices::DeviceId;
13*bb4ee6a4SAndroid Build Coastguard Worker use devices::IrqChip;
14*bb4ee6a4SAndroid Build Coastguard Worker use devices::IrqChipX86_64;
15*bb4ee6a4SAndroid Build Coastguard Worker use devices::IrqEdgeEvent;
16*bb4ee6a4SAndroid Build Coastguard Worker use devices::IrqEventSource;
17*bb4ee6a4SAndroid Build Coastguard Worker use devices::IrqLevelEvent;
18*bb4ee6a4SAndroid Build Coastguard Worker use devices::WhpxSplitIrqChip;
19*bb4ee6a4SAndroid Build Coastguard Worker use devices::IOAPIC_BASE_ADDRESS;
20*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::Whpx;
21*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::WhpxFeature;
22*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::WhpxVm;
23*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::CpuId;
24*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IoapicRedirectionTableEntry;
25*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IrqRoute;
26*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IrqSource;
27*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PicSelect;
28*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PitRWMode;
29*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::TriggerMode;
30*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Vm;
31*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::VmX86_64;
32*bb4ee6a4SAndroid Build Coastguard Worker use resources::AddressRange;
33*bb4ee6a4SAndroid Build Coastguard Worker use resources::SystemAllocator;
34*bb4ee6a4SAndroid Build Coastguard Worker use resources::SystemAllocatorConfig;
35*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
36*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
37*bb4ee6a4SAndroid Build Coastguard Worker 
38*bb4ee6a4SAndroid Build Coastguard Worker use crate::x86_64::test_get_ioapic;
39*bb4ee6a4SAndroid Build Coastguard Worker use crate::x86_64::test_get_pit;
40*bb4ee6a4SAndroid Build Coastguard Worker use crate::x86_64::test_route_irq;
41*bb4ee6a4SAndroid Build Coastguard Worker use crate::x86_64::test_set_ioapic;
42*bb4ee6a4SAndroid Build Coastguard Worker use crate::x86_64::test_set_pic;
43*bb4ee6a4SAndroid Build Coastguard Worker use crate::x86_64::test_set_pit;
44*bb4ee6a4SAndroid Build Coastguard Worker 
split_supported() -> bool45*bb4ee6a4SAndroid Build Coastguard Worker fn split_supported() -> bool {
46*bb4ee6a4SAndroid Build Coastguard Worker     Whpx::check_whpx_feature(WhpxFeature::LocalApicEmulation).expect("failed to get whpx features")
47*bb4ee6a4SAndroid Build Coastguard Worker }
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker /// Helper function for setting up a WhpxSplitIrqChip.
get_chip(num_vcpus: usize) -> WhpxSplitIrqChip50*bb4ee6a4SAndroid Build Coastguard Worker fn get_chip(num_vcpus: usize) -> WhpxSplitIrqChip {
51*bb4ee6a4SAndroid Build Coastguard Worker     let whpx = Whpx::new().expect("failed to instantiate Whpx");
52*bb4ee6a4SAndroid Build Coastguard Worker     let mem = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
53*bb4ee6a4SAndroid Build Coastguard Worker     let vm = WhpxVm::new(&whpx, num_vcpus, mem, CpuId::new(0), true, None)
54*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to instantiate vm");
55*bb4ee6a4SAndroid Build Coastguard Worker 
56*bb4ee6a4SAndroid Build Coastguard Worker     let (_, irq_tube) = Tube::pair().expect("failed to create irq tube");
57*bb4ee6a4SAndroid Build Coastguard Worker 
58*bb4ee6a4SAndroid Build Coastguard Worker     let mut chip =
59*bb4ee6a4SAndroid Build Coastguard Worker         WhpxSplitIrqChip::new(vm.try_clone().expect("failed to clone vm"), irq_tube, None)
60*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to instantiate WhpxSplitIrqChip");
61*bb4ee6a4SAndroid Build Coastguard Worker 
62*bb4ee6a4SAndroid Build Coastguard Worker     for i in 0..num_vcpus {
63*bb4ee6a4SAndroid Build Coastguard Worker         let vcpu = vm.create_vcpu(i).expect("failed to instantiate vcpu");
64*bb4ee6a4SAndroid Build Coastguard Worker         chip.add_vcpu(i, vcpu.as_vcpu())
65*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to add vcpu");
66*bb4ee6a4SAndroid Build Coastguard Worker     }
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker     chip
69*bb4ee6a4SAndroid Build Coastguard Worker }
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker #[test]
set_pic()72*bb4ee6a4SAndroid Build Coastguard Worker fn set_pic() {
73*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
74*bb4ee6a4SAndroid Build Coastguard Worker         return;
75*bb4ee6a4SAndroid Build Coastguard Worker     }
76*bb4ee6a4SAndroid Build Coastguard Worker     test_set_pic(get_chip(1));
77*bb4ee6a4SAndroid Build Coastguard Worker }
78*bb4ee6a4SAndroid Build Coastguard Worker 
79*bb4ee6a4SAndroid Build Coastguard Worker #[test]
get_ioapic()80*bb4ee6a4SAndroid Build Coastguard Worker fn get_ioapic() {
81*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
82*bb4ee6a4SAndroid Build Coastguard Worker         return;
83*bb4ee6a4SAndroid Build Coastguard Worker     }
84*bb4ee6a4SAndroid Build Coastguard Worker     test_get_ioapic(get_chip(1));
85*bb4ee6a4SAndroid Build Coastguard Worker }
86*bb4ee6a4SAndroid Build Coastguard Worker 
87*bb4ee6a4SAndroid Build Coastguard Worker #[test]
set_ioapic()88*bb4ee6a4SAndroid Build Coastguard Worker fn set_ioapic() {
89*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
90*bb4ee6a4SAndroid Build Coastguard Worker         return;
91*bb4ee6a4SAndroid Build Coastguard Worker     }
92*bb4ee6a4SAndroid Build Coastguard Worker     test_set_ioapic(get_chip(1));
93*bb4ee6a4SAndroid Build Coastguard Worker }
94*bb4ee6a4SAndroid Build Coastguard Worker 
95*bb4ee6a4SAndroid Build Coastguard Worker #[test]
get_pit()96*bb4ee6a4SAndroid Build Coastguard Worker fn get_pit() {
97*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
98*bb4ee6a4SAndroid Build Coastguard Worker         return;
99*bb4ee6a4SAndroid Build Coastguard Worker     }
100*bb4ee6a4SAndroid Build Coastguard Worker     test_get_pit(get_chip(1));
101*bb4ee6a4SAndroid Build Coastguard Worker }
102*bb4ee6a4SAndroid Build Coastguard Worker 
103*bb4ee6a4SAndroid Build Coastguard Worker #[test]
set_pit()104*bb4ee6a4SAndroid Build Coastguard Worker fn set_pit() {
105*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
106*bb4ee6a4SAndroid Build Coastguard Worker         return;
107*bb4ee6a4SAndroid Build Coastguard Worker     }
108*bb4ee6a4SAndroid Build Coastguard Worker     test_set_pit(get_chip(1));
109*bb4ee6a4SAndroid Build Coastguard Worker }
110*bb4ee6a4SAndroid Build Coastguard Worker 
111*bb4ee6a4SAndroid Build Coastguard Worker #[test]
route_irq()112*bb4ee6a4SAndroid Build Coastguard Worker fn route_irq() {
113*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
114*bb4ee6a4SAndroid Build Coastguard Worker         return;
115*bb4ee6a4SAndroid Build Coastguard Worker     }
116*bb4ee6a4SAndroid Build Coastguard Worker     test_route_irq(get_chip(1));
117*bb4ee6a4SAndroid Build Coastguard Worker }
118*bb4ee6a4SAndroid Build Coastguard Worker 
119*bb4ee6a4SAndroid Build Coastguard Worker #[test]
pit_uses_speaker_port()120*bb4ee6a4SAndroid Build Coastguard Worker fn pit_uses_speaker_port() {
121*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
122*bb4ee6a4SAndroid Build Coastguard Worker         return;
123*bb4ee6a4SAndroid Build Coastguard Worker     }
124*bb4ee6a4SAndroid Build Coastguard Worker     let chip = get_chip(1);
125*bb4ee6a4SAndroid Build Coastguard Worker     assert!(chip.pit_uses_speaker_port());
126*bb4ee6a4SAndroid Build Coastguard Worker }
127*bb4ee6a4SAndroid Build Coastguard Worker 
128*bb4ee6a4SAndroid Build Coastguard Worker #[test]
routes_conflict()129*bb4ee6a4SAndroid Build Coastguard Worker fn routes_conflict() {
130*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
131*bb4ee6a4SAndroid Build Coastguard Worker         return;
132*bb4ee6a4SAndroid Build Coastguard Worker     }
133*bb4ee6a4SAndroid Build Coastguard Worker     let mut chip = get_chip(1);
134*bb4ee6a4SAndroid Build Coastguard Worker     chip.route_irq(IrqRoute {
135*bb4ee6a4SAndroid Build Coastguard Worker         gsi: 32,
136*bb4ee6a4SAndroid Build Coastguard Worker         source: IrqSource::Msi {
137*bb4ee6a4SAndroid Build Coastguard Worker             address: 4276092928,
138*bb4ee6a4SAndroid Build Coastguard Worker             data: 0,
139*bb4ee6a4SAndroid Build Coastguard Worker         },
140*bb4ee6a4SAndroid Build Coastguard Worker     })
141*bb4ee6a4SAndroid Build Coastguard Worker     .expect("failed to set msi route");
142*bb4ee6a4SAndroid Build Coastguard Worker     // this second route should replace the first
143*bb4ee6a4SAndroid Build Coastguard Worker     chip.route_irq(IrqRoute {
144*bb4ee6a4SAndroid Build Coastguard Worker         gsi: 32,
145*bb4ee6a4SAndroid Build Coastguard Worker         source: IrqSource::Msi {
146*bb4ee6a4SAndroid Build Coastguard Worker             address: 4276092928,
147*bb4ee6a4SAndroid Build Coastguard Worker             data: 32801,
148*bb4ee6a4SAndroid Build Coastguard Worker         },
149*bb4ee6a4SAndroid Build Coastguard Worker     })
150*bb4ee6a4SAndroid Build Coastguard Worker     .expect("failed to set msi route");
151*bb4ee6a4SAndroid Build Coastguard Worker }
152*bb4ee6a4SAndroid Build Coastguard Worker 
153*bb4ee6a4SAndroid Build Coastguard Worker #[test]
irq_event_tokens()154*bb4ee6a4SAndroid Build Coastguard Worker fn irq_event_tokens() {
155*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
156*bb4ee6a4SAndroid Build Coastguard Worker         return;
157*bb4ee6a4SAndroid Build Coastguard Worker     }
158*bb4ee6a4SAndroid Build Coastguard Worker     let mut chip = get_chip(1);
159*bb4ee6a4SAndroid Build Coastguard Worker     let tokens = chip
160*bb4ee6a4SAndroid Build Coastguard Worker         .irq_event_tokens()
161*bb4ee6a4SAndroid Build Coastguard Worker         .expect("could not get irq_event_tokens");
162*bb4ee6a4SAndroid Build Coastguard Worker 
163*bb4ee6a4SAndroid Build Coastguard Worker     // there should be one token on a fresh split irqchip, for the pit
164*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(tokens.len(), 1);
165*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(tokens[0].1.device_name, "userspace PIT");
166*bb4ee6a4SAndroid Build Coastguard Worker 
167*bb4ee6a4SAndroid Build Coastguard Worker     // register another irq event
168*bb4ee6a4SAndroid Build Coastguard Worker     let evt = IrqEdgeEvent::new().expect("failed to create event");
169*bb4ee6a4SAndroid Build Coastguard Worker     let source = IrqEventSource {
170*bb4ee6a4SAndroid Build Coastguard Worker         device_id: CrosvmDeviceId::DebugConsole.into(),
171*bb4ee6a4SAndroid Build Coastguard Worker         queue_id: 0,
172*bb4ee6a4SAndroid Build Coastguard Worker         device_name: "test".to_owned(),
173*bb4ee6a4SAndroid Build Coastguard Worker     };
174*bb4ee6a4SAndroid Build Coastguard Worker     chip.register_edge_irq_event(6, &evt, source)
175*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to register irq event");
176*bb4ee6a4SAndroid Build Coastguard Worker 
177*bb4ee6a4SAndroid Build Coastguard Worker     let tokens = chip
178*bb4ee6a4SAndroid Build Coastguard Worker         .irq_event_tokens()
179*bb4ee6a4SAndroid Build Coastguard Worker         .expect("could not get irq_event_tokens");
180*bb4ee6a4SAndroid Build Coastguard Worker 
181*bb4ee6a4SAndroid Build Coastguard Worker     // now there should be two tokens
182*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(tokens.len(), 2);
183*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(tokens[0].1.device_name, "userspace PIT");
184*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
185*bb4ee6a4SAndroid Build Coastguard Worker         tokens[1].1.device_id,
186*bb4ee6a4SAndroid Build Coastguard Worker         DeviceId::PlatformDeviceId(CrosvmDeviceId::DebugConsole)
187*bb4ee6a4SAndroid Build Coastguard Worker     );
188*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(tokens[1].2, evt.get_trigger().try_clone().unwrap());
189*bb4ee6a4SAndroid Build Coastguard Worker }
190*bb4ee6a4SAndroid Build Coastguard Worker 
191*bb4ee6a4SAndroid Build Coastguard Worker // TODO(srichman): Factor out of UserspaceIrqChip and KvmSplitIrqChip and WhpxSplitIrqChip.
192*bb4ee6a4SAndroid Build Coastguard Worker #[test]
finalize_devices()193*bb4ee6a4SAndroid Build Coastguard Worker fn finalize_devices() {
194*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
195*bb4ee6a4SAndroid Build Coastguard Worker         return;
196*bb4ee6a4SAndroid Build Coastguard Worker     }
197*bb4ee6a4SAndroid Build Coastguard Worker     let mut chip = get_chip(1);
198*bb4ee6a4SAndroid Build Coastguard Worker 
199*bb4ee6a4SAndroid Build Coastguard Worker     let mmio_bus = Bus::new(BusType::Mmio);
200*bb4ee6a4SAndroid Build Coastguard Worker     let io_bus = Bus::new(BusType::Io);
201*bb4ee6a4SAndroid Build Coastguard Worker     let mut resources = SystemAllocator::new(
202*bb4ee6a4SAndroid Build Coastguard Worker         SystemAllocatorConfig {
203*bb4ee6a4SAndroid Build Coastguard Worker             io: Some(AddressRange {
204*bb4ee6a4SAndroid Build Coastguard Worker                 start: 0xc000,
205*bb4ee6a4SAndroid Build Coastguard Worker                 end: 0xFFFF,
206*bb4ee6a4SAndroid Build Coastguard Worker             }),
207*bb4ee6a4SAndroid Build Coastguard Worker             low_mmio: AddressRange {
208*bb4ee6a4SAndroid Build Coastguard Worker                 start: 0,
209*bb4ee6a4SAndroid Build Coastguard Worker                 end: 2048,
210*bb4ee6a4SAndroid Build Coastguard Worker             },
211*bb4ee6a4SAndroid Build Coastguard Worker             high_mmio: AddressRange {
212*bb4ee6a4SAndroid Build Coastguard Worker                 start: 2048,
213*bb4ee6a4SAndroid Build Coastguard Worker                 end: 6143,
214*bb4ee6a4SAndroid Build Coastguard Worker             },
215*bb4ee6a4SAndroid Build Coastguard Worker             platform_mmio: None,
216*bb4ee6a4SAndroid Build Coastguard Worker             first_irq: 5,
217*bb4ee6a4SAndroid Build Coastguard Worker         },
218*bb4ee6a4SAndroid Build Coastguard Worker         None,
219*bb4ee6a4SAndroid Build Coastguard Worker         &[],
220*bb4ee6a4SAndroid Build Coastguard Worker     )
221*bb4ee6a4SAndroid Build Coastguard Worker     .expect("failed to create SystemAllocator");
222*bb4ee6a4SAndroid Build Coastguard Worker 
223*bb4ee6a4SAndroid Build Coastguard Worker     // setup an event for irq line 1
224*bb4ee6a4SAndroid Build Coastguard Worker     let evt = IrqLevelEvent::new().expect("failed to create event");
225*bb4ee6a4SAndroid Build Coastguard Worker 
226*bb4ee6a4SAndroid Build Coastguard Worker     let source = IrqEventSource {
227*bb4ee6a4SAndroid Build Coastguard Worker         device_id: CrosvmDeviceId::DebugConsole.into(),
228*bb4ee6a4SAndroid Build Coastguard Worker         device_name: "test".to_owned(),
229*bb4ee6a4SAndroid Build Coastguard Worker         queue_id: 0,
230*bb4ee6a4SAndroid Build Coastguard Worker     };
231*bb4ee6a4SAndroid Build Coastguard Worker 
232*bb4ee6a4SAndroid Build Coastguard Worker     let evt_index = chip
233*bb4ee6a4SAndroid Build Coastguard Worker         .register_level_irq_event(1, &evt, source)
234*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to register_level_irq_event")
235*bb4ee6a4SAndroid Build Coastguard Worker         .expect("register_level_irq_event should not return None");
236*bb4ee6a4SAndroid Build Coastguard Worker 
237*bb4ee6a4SAndroid Build Coastguard Worker     // Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses
238*bb4ee6a4SAndroid Build Coastguard Worker     chip.finalize_devices(&mut resources, &io_bus, &mmio_bus)
239*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to finalize devices");
240*bb4ee6a4SAndroid Build Coastguard Worker 
241*bb4ee6a4SAndroid Build Coastguard Worker     // Should not be able to allocate an irq < 24 now
242*bb4ee6a4SAndroid Build Coastguard Worker     assert!(resources.allocate_irq().expect("failed to allocate irq") >= 24);
243*bb4ee6a4SAndroid Build Coastguard Worker 
244*bb4ee6a4SAndroid Build Coastguard Worker     // set PIT counter 2 to "SquareWaveGen"(aka 3) mode and "Both" access mode
245*bb4ee6a4SAndroid Build Coastguard Worker     io_bus.write(0x43, &[0b10110110]);
246*bb4ee6a4SAndroid Build Coastguard Worker 
247*bb4ee6a4SAndroid Build Coastguard Worker     let state = chip.get_pit().expect("failed to get pit state");
248*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(state.channels[2].mode, 3);
249*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(state.channels[2].rw_mode, PitRWMode::Both);
250*bb4ee6a4SAndroid Build Coastguard Worker 
251*bb4ee6a4SAndroid Build Coastguard Worker     // ICW1 0x11: Edge trigger, cascade mode, ICW4 needed.
252*bb4ee6a4SAndroid Build Coastguard Worker     // ICW2 0x08: Interrupt vector base address 0x08.
253*bb4ee6a4SAndroid Build Coastguard Worker     // ICW3 0xff: Value written does not matter.
254*bb4ee6a4SAndroid Build Coastguard Worker     // ICW4 0x13: Special fully nested mode, auto EOI.
255*bb4ee6a4SAndroid Build Coastguard Worker     io_bus.write(0x20, &[0x11]);
256*bb4ee6a4SAndroid Build Coastguard Worker     io_bus.write(0x21, &[0x08]);
257*bb4ee6a4SAndroid Build Coastguard Worker     io_bus.write(0x21, &[0xff]);
258*bb4ee6a4SAndroid Build Coastguard Worker     io_bus.write(0x21, &[0x13]);
259*bb4ee6a4SAndroid Build Coastguard Worker 
260*bb4ee6a4SAndroid Build Coastguard Worker     let state = chip
261*bb4ee6a4SAndroid Build Coastguard Worker         .get_pic_state(PicSelect::Primary)
262*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to get pic state");
263*bb4ee6a4SAndroid Build Coastguard Worker 
264*bb4ee6a4SAndroid Build Coastguard Worker     // auto eoi and special fully nested mode should be turned on
265*bb4ee6a4SAndroid Build Coastguard Worker     assert!(state.auto_eoi);
266*bb4ee6a4SAndroid Build Coastguard Worker     assert!(state.special_fully_nested_mode);
267*bb4ee6a4SAndroid Build Coastguard Worker 
268*bb4ee6a4SAndroid Build Coastguard Worker     // Need to write to the irq event before servicing it
269*bb4ee6a4SAndroid Build Coastguard Worker     evt.trigger().expect("failed to write to event");
270*bb4ee6a4SAndroid Build Coastguard Worker 
271*bb4ee6a4SAndroid Build Coastguard Worker     // if we assert irq line one, and then get the resulting interrupt, an auto-eoi should
272*bb4ee6a4SAndroid Build Coastguard Worker     // occur and cause the resample_event to be written to
273*bb4ee6a4SAndroid Build Coastguard Worker     chip.service_irq_event(evt_index)
274*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to service irq");
275*bb4ee6a4SAndroid Build Coastguard Worker 
276*bb4ee6a4SAndroid Build Coastguard Worker     assert!(chip.interrupt_requested(0));
277*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
278*bb4ee6a4SAndroid Build Coastguard Worker         chip.get_external_interrupt(0)
279*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to get external interrupt"),
280*bb4ee6a4SAndroid Build Coastguard Worker         // Vector is 9 because the interrupt vector base address is 0x08 and this is irq
281*bb4ee6a4SAndroid Build Coastguard Worker         // line 1 and 8+1 = 9
282*bb4ee6a4SAndroid Build Coastguard Worker         Some(0x9)
283*bb4ee6a4SAndroid Build Coastguard Worker     );
284*bb4ee6a4SAndroid Build Coastguard Worker 
285*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
286*bb4ee6a4SAndroid Build Coastguard Worker         evt.get_resample()
287*bb4ee6a4SAndroid Build Coastguard Worker             .wait_timeout(std::time::Duration::from_secs(1))
288*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to read_timeout"),
289*bb4ee6a4SAndroid Build Coastguard Worker         EventWaitResult::Signaled
290*bb4ee6a4SAndroid Build Coastguard Worker     );
291*bb4ee6a4SAndroid Build Coastguard Worker 
292*bb4ee6a4SAndroid Build Coastguard Worker     // setup a ioapic redirection table entry 14
293*bb4ee6a4SAndroid Build Coastguard Worker     let mut entry = IoapicRedirectionTableEntry::default();
294*bb4ee6a4SAndroid Build Coastguard Worker     entry.set_vector(44);
295*bb4ee6a4SAndroid Build Coastguard Worker 
296*bb4ee6a4SAndroid Build Coastguard Worker     let irq_14_offset = 0x10 + 14 * 2;
297*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_14_offset]);
298*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(
299*bb4ee6a4SAndroid Build Coastguard Worker         IOAPIC_BASE_ADDRESS + 0x10,
300*bb4ee6a4SAndroid Build Coastguard Worker         &(entry.get(0, 32) as u32).to_ne_bytes(),
301*bb4ee6a4SAndroid Build Coastguard Worker     );
302*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_14_offset + 1]);
303*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(
304*bb4ee6a4SAndroid Build Coastguard Worker         IOAPIC_BASE_ADDRESS + 0x10,
305*bb4ee6a4SAndroid Build Coastguard Worker         &(entry.get(32, 32) as u32).to_ne_bytes(),
306*bb4ee6a4SAndroid Build Coastguard Worker     );
307*bb4ee6a4SAndroid Build Coastguard Worker 
308*bb4ee6a4SAndroid Build Coastguard Worker     let state = chip.get_ioapic_state().expect("failed to get ioapic state");
309*bb4ee6a4SAndroid Build Coastguard Worker 
310*bb4ee6a4SAndroid Build Coastguard Worker     // redirection table entry 14 should have a vector of 44
311*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(state.redirect_table[14].get_vector(), 44);
312*bb4ee6a4SAndroid Build Coastguard Worker }
313*bb4ee6a4SAndroid Build Coastguard Worker 
314*bb4ee6a4SAndroid Build Coastguard Worker // TODO(srichman): Factor out of UserspaceIrqChip and KvmSplitIrqChip and WhpxSplitIrqChip.
315*bb4ee6a4SAndroid Build Coastguard Worker #[test]
broadcast_eoi()316*bb4ee6a4SAndroid Build Coastguard Worker fn broadcast_eoi() {
317*bb4ee6a4SAndroid Build Coastguard Worker     if !split_supported() {
318*bb4ee6a4SAndroid Build Coastguard Worker         return;
319*bb4ee6a4SAndroid Build Coastguard Worker     }
320*bb4ee6a4SAndroid Build Coastguard Worker     let mut chip = get_chip(1);
321*bb4ee6a4SAndroid Build Coastguard Worker 
322*bb4ee6a4SAndroid Build Coastguard Worker     let mmio_bus = Bus::new(BusType::Mmio);
323*bb4ee6a4SAndroid Build Coastguard Worker     let io_bus = Bus::new(BusType::Io);
324*bb4ee6a4SAndroid Build Coastguard Worker     let mut resources = SystemAllocator::new(
325*bb4ee6a4SAndroid Build Coastguard Worker         SystemAllocatorConfig {
326*bb4ee6a4SAndroid Build Coastguard Worker             io: Some(AddressRange {
327*bb4ee6a4SAndroid Build Coastguard Worker                 start: 0xc000,
328*bb4ee6a4SAndroid Build Coastguard Worker                 end: 0xFFFF,
329*bb4ee6a4SAndroid Build Coastguard Worker             }),
330*bb4ee6a4SAndroid Build Coastguard Worker             low_mmio: AddressRange {
331*bb4ee6a4SAndroid Build Coastguard Worker                 start: 0,
332*bb4ee6a4SAndroid Build Coastguard Worker                 end: 2048,
333*bb4ee6a4SAndroid Build Coastguard Worker             },
334*bb4ee6a4SAndroid Build Coastguard Worker             high_mmio: AddressRange {
335*bb4ee6a4SAndroid Build Coastguard Worker                 start: 2048,
336*bb4ee6a4SAndroid Build Coastguard Worker                 end: 6143,
337*bb4ee6a4SAndroid Build Coastguard Worker             },
338*bb4ee6a4SAndroid Build Coastguard Worker             platform_mmio: None,
339*bb4ee6a4SAndroid Build Coastguard Worker             first_irq: 5,
340*bb4ee6a4SAndroid Build Coastguard Worker         },
341*bb4ee6a4SAndroid Build Coastguard Worker         None,
342*bb4ee6a4SAndroid Build Coastguard Worker         &[],
343*bb4ee6a4SAndroid Build Coastguard Worker     )
344*bb4ee6a4SAndroid Build Coastguard Worker     .expect("failed to create SystemAllocator");
345*bb4ee6a4SAndroid Build Coastguard Worker 
346*bb4ee6a4SAndroid Build Coastguard Worker     // setup an event for irq line 1
347*bb4ee6a4SAndroid Build Coastguard Worker     let evt = IrqLevelEvent::new().expect("failed to create event");
348*bb4ee6a4SAndroid Build Coastguard Worker 
349*bb4ee6a4SAndroid Build Coastguard Worker     let source = IrqEventSource {
350*bb4ee6a4SAndroid Build Coastguard Worker         device_id: CrosvmDeviceId::DebugConsole.into(),
351*bb4ee6a4SAndroid Build Coastguard Worker         device_name: "test".to_owned(),
352*bb4ee6a4SAndroid Build Coastguard Worker         queue_id: 0,
353*bb4ee6a4SAndroid Build Coastguard Worker     };
354*bb4ee6a4SAndroid Build Coastguard Worker 
355*bb4ee6a4SAndroid Build Coastguard Worker     chip.register_level_irq_event(1, &evt, source)
356*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to register_level_irq_event");
357*bb4ee6a4SAndroid Build Coastguard Worker 
358*bb4ee6a4SAndroid Build Coastguard Worker     // Once we finalize devices, the pic/pit/ioapic should be attached to io and mmio busses
359*bb4ee6a4SAndroid Build Coastguard Worker     chip.finalize_devices(&mut resources, &io_bus, &mmio_bus)
360*bb4ee6a4SAndroid Build Coastguard Worker         .expect("failed to finalize devices");
361*bb4ee6a4SAndroid Build Coastguard Worker 
362*bb4ee6a4SAndroid Build Coastguard Worker     // setup a ioapic redirection table entry 1 with a vector of 123
363*bb4ee6a4SAndroid Build Coastguard Worker     let mut entry = IoapicRedirectionTableEntry::default();
364*bb4ee6a4SAndroid Build Coastguard Worker     entry.set_vector(123);
365*bb4ee6a4SAndroid Build Coastguard Worker     entry.set_trigger_mode(TriggerMode::Level);
366*bb4ee6a4SAndroid Build Coastguard Worker 
367*bb4ee6a4SAndroid Build Coastguard Worker     let irq_write_offset = 0x10 + 1 * 2;
368*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_write_offset]);
369*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(
370*bb4ee6a4SAndroid Build Coastguard Worker         IOAPIC_BASE_ADDRESS + 0x10,
371*bb4ee6a4SAndroid Build Coastguard Worker         &(entry.get(0, 32) as u32).to_ne_bytes(),
372*bb4ee6a4SAndroid Build Coastguard Worker     );
373*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(IOAPIC_BASE_ADDRESS, &[irq_write_offset + 1]);
374*bb4ee6a4SAndroid Build Coastguard Worker     mmio_bus.write(
375*bb4ee6a4SAndroid Build Coastguard Worker         IOAPIC_BASE_ADDRESS + 0x10,
376*bb4ee6a4SAndroid Build Coastguard Worker         &(entry.get(32, 32) as u32).to_ne_bytes(),
377*bb4ee6a4SAndroid Build Coastguard Worker     );
378*bb4ee6a4SAndroid Build Coastguard Worker 
379*bb4ee6a4SAndroid Build Coastguard Worker     // Assert line 1
380*bb4ee6a4SAndroid Build Coastguard Worker     chip.service_irq(1, true).expect("failed to service irq");
381*bb4ee6a4SAndroid Build Coastguard Worker 
382*bb4ee6a4SAndroid Build Coastguard Worker     // resample event should not be written to
383*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
384*bb4ee6a4SAndroid Build Coastguard Worker         evt.get_resample()
385*bb4ee6a4SAndroid Build Coastguard Worker             .wait_timeout(std::time::Duration::from_millis(10))
386*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to read_timeout"),
387*bb4ee6a4SAndroid Build Coastguard Worker         EventWaitResult::TimedOut
388*bb4ee6a4SAndroid Build Coastguard Worker     );
389*bb4ee6a4SAndroid Build Coastguard Worker 
390*bb4ee6a4SAndroid Build Coastguard Worker     // irq line 1 should be asserted
391*bb4ee6a4SAndroid Build Coastguard Worker     let state = chip.get_ioapic_state().expect("failed to get ioapic state");
392*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(state.current_interrupt_level_bitmap, 1 << 1);
393*bb4ee6a4SAndroid Build Coastguard Worker 
394*bb4ee6a4SAndroid Build Coastguard Worker     // Now broadcast an eoi for vector 123
395*bb4ee6a4SAndroid Build Coastguard Worker     chip.broadcast_eoi(123).expect("failed to broadcast eoi");
396*bb4ee6a4SAndroid Build Coastguard Worker 
397*bb4ee6a4SAndroid Build Coastguard Worker     // irq line 1 should be deasserted
398*bb4ee6a4SAndroid Build Coastguard Worker     let state = chip.get_ioapic_state().expect("failed to get ioapic state");
399*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(state.current_interrupt_level_bitmap, 0);
400*bb4ee6a4SAndroid Build Coastguard Worker 
401*bb4ee6a4SAndroid Build Coastguard Worker     // resample event should be written to by ioapic
402*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
403*bb4ee6a4SAndroid Build Coastguard Worker         evt.get_resample()
404*bb4ee6a4SAndroid Build Coastguard Worker             .wait_timeout(std::time::Duration::from_millis(10))
405*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to read_timeout"),
406*bb4ee6a4SAndroid Build Coastguard Worker         EventWaitResult::Signaled
407*bb4ee6a4SAndroid Build Coastguard Worker     );
408*bb4ee6a4SAndroid Build Coastguard Worker }
409