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