1 // Copyright 2020, ARM Limited. 2 // 3 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 4 5 use super::interrupt_controller::{Error, InterruptController}; 6 extern crate arch; 7 use anyhow::anyhow; 8 use arch::layout; 9 use hypervisor::{ 10 arch::aarch64::gic::{Vgic, VgicConfig}, 11 CpuState, GicState, 12 }; 13 use std::result; 14 use std::sync::{Arc, Mutex}; 15 use vm_device::interrupt::{ 16 InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup, 17 LegacyIrqSourceConfig, MsiIrqGroupConfig, 18 }; 19 use vm_memory::address::Address; 20 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; 21 use vmm_sys_util::eventfd::EventFd; 22 23 type Result<T> = result::Result<T, Error>; 24 25 // Reserve 32 IRQs for legacy devices. 26 pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize; 27 pub const IRQ_LEGACY_COUNT: usize = 32; 28 pub const GIC_SNAPSHOT_ID: &str = "gic-v3-its"; 29 30 // Gic (Generic Interrupt Controller) struct provides all the functionality of a 31 // GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the 32 // `hypervisor` crate. 33 // Gic struct also implements InterruptController to provide interrupt delivery 34 // service. 35 pub struct Gic { 36 interrupt_source_group: Arc<dyn InterruptSourceGroup>, 37 // The hypervisor agnostic virtual GIC 38 vgic: Option<Arc<Mutex<dyn Vgic>>>, 39 } 40 41 impl Gic { 42 pub fn new( 43 vcpu_count: u8, 44 interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>, 45 vm: Arc<dyn hypervisor::Vm>, 46 ) -> Result<Gic> { 47 let interrupt_source_group = interrupt_manager 48 .create_group(MsiIrqGroupConfig { 49 base: IRQ_LEGACY_BASE as InterruptIndex, 50 count: IRQ_LEGACY_COUNT as InterruptIndex, 51 }) 52 .map_err(Error::CreateInterruptSourceGroup)?; 53 54 let vgic = vm 55 .create_vgic(Gic::create_default_config(vcpu_count as u64)) 56 .map_err(Error::CreateGic)?; 57 58 let gic = Gic { 59 interrupt_source_group, 60 vgic: Some(vgic), 61 }; 62 gic.enable()?; 63 64 Ok(gic) 65 } 66 67 pub fn restore_vgic( 68 &mut self, 69 state: Option<GicState>, 70 saved_vcpu_states: &[CpuState], 71 ) -> Result<()> { 72 self.set_gicr_typers(saved_vcpu_states); 73 self.vgic 74 .clone() 75 .unwrap() 76 .lock() 77 .unwrap() 78 .set_state(&state.unwrap()) 79 .map_err(Error::RestoreGic) 80 } 81 82 fn enable(&self) -> Result<()> { 83 // Set irqfd for legacy interrupts 84 self.interrupt_source_group 85 .enable() 86 .map_err(Error::EnableInterrupt)?; 87 88 // Set irq_routing for legacy interrupts. 89 // irqchip: Hardcode to 0 as we support only 1 GIC 90 // pin: Use irq number as pin 91 for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) { 92 let config = LegacyIrqSourceConfig { 93 irqchip: 0, 94 pin: (i - IRQ_LEGACY_BASE) as u32, 95 }; 96 self.interrupt_source_group 97 .update( 98 i as InterruptIndex, 99 InterruptSourceConfig::LegacyIrq(config), 100 false, 101 false, 102 ) 103 .map_err(Error::EnableInterrupt)?; 104 } 105 106 self.interrupt_source_group 107 .set_gsi() 108 .map_err(Error::EnableInterrupt)?; 109 Ok(()) 110 } 111 112 /// Default config implied by arch::layout 113 pub fn create_default_config(vcpu_count: u64) -> VgicConfig { 114 let redists_size = layout::GIC_V3_REDIST_SIZE * vcpu_count; 115 let redists_addr = layout::GIC_V3_DIST_START.raw_value() - redists_size; 116 VgicConfig { 117 vcpu_count, 118 dist_addr: layout::GIC_V3_DIST_START.raw_value(), 119 dist_size: layout::GIC_V3_DIST_SIZE, 120 redists_addr, 121 redists_size, 122 msi_addr: redists_addr - layout::GIC_V3_ITS_SIZE, 123 msi_size: layout::GIC_V3_ITS_SIZE, 124 nr_irqs: layout::IRQ_NUM, 125 } 126 } 127 128 pub fn get_vgic(&mut self) -> Result<Arc<Mutex<dyn Vgic>>> { 129 Ok(self.vgic.clone().unwrap()) 130 } 131 132 pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) { 133 let vgic = self.vgic.as_ref().unwrap().clone(); 134 vgic.lock().unwrap().set_gicr_typers(vcpu_states); 135 } 136 } 137 138 impl InterruptController for Gic { 139 // This should be called anytime an interrupt needs to be injected into the 140 // running guest. 141 fn service_irq(&mut self, irq: usize) -> Result<()> { 142 self.interrupt_source_group 143 .trigger(irq as InterruptIndex) 144 .map_err(Error::TriggerInterrupt)?; 145 146 Ok(()) 147 } 148 149 fn notifier(&self, irq: usize) -> Option<EventFd> { 150 self.interrupt_source_group.notifier(irq as InterruptIndex) 151 } 152 } 153 154 impl Snapshottable for Gic { 155 fn id(&self) -> String { 156 GIC_SNAPSHOT_ID.to_string() 157 } 158 159 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 160 let vgic = self.vgic.as_ref().unwrap().clone(); 161 let state = vgic.lock().unwrap().state().unwrap(); 162 Snapshot::new_from_state(&state) 163 } 164 } 165 166 impl Pausable for Gic { 167 fn pause(&mut self) -> std::result::Result<(), MigratableError> { 168 // Flush tables to guest RAM 169 let vgic = self.vgic.as_ref().unwrap().clone(); 170 vgic.lock().unwrap().save_data_tables().map_err(|e| { 171 MigratableError::Pause(anyhow!( 172 "Could not save GICv3ITS GIC pending tables {:?}", 173 e 174 )) 175 })?; 176 Ok(()) 177 } 178 } 179 impl Transportable for Gic {} 180 impl Migratable for Gic {} 181