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