1
0

x86_64.rs 13 KB

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