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