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