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, 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 29 // Gic (Generic Interupt 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 ) -> Result<Gic> { 45 let interrupt_source_group = interrupt_manager 46 .create_group(MsiIrqGroupConfig { 47 base: IRQ_LEGACY_BASE as InterruptIndex, 48 count: IRQ_LEGACY_COUNT as InterruptIndex, 49 }) 50 .map_err(Error::CreateInterruptSourceGroup)?; 51 52 Ok(Gic { 53 interrupt_source_group, 54 vgic: None, 55 }) 56 } 57 58 /// Default config implied by arch::layout 59 pub fn create_default_config(vcpu_count: u64) -> VgicConfig { 60 let redists_size = layout::GIC_V3_REDIST_SIZE * vcpu_count; 61 let redists_addr = layout::GIC_V3_DIST_START.raw_value() - redists_size; 62 VgicConfig { 63 vcpu_count, 64 dist_addr: layout::GIC_V3_DIST_START.raw_value(), 65 dist_size: layout::GIC_V3_DIST_SIZE, 66 redists_addr, 67 redists_size, 68 msi_addr: redists_addr - layout::GIC_V3_ITS_SIZE, 69 msi_size: layout::GIC_V3_ITS_SIZE, 70 nr_irqs: layout::IRQ_NUM, 71 } 72 } 73 74 pub fn create_vgic( 75 &mut self, 76 vm: &Arc<dyn hypervisor::Vm>, 77 config: VgicConfig, 78 ) -> Result<Arc<Mutex<dyn Vgic>>> { 79 let vgic = vm.create_vgic(config).map_err(Error::CreateGic)?; 80 self.vgic = Some(vgic.clone()); 81 Ok(vgic.clone()) 82 } 83 84 pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) { 85 let vgic = self.vgic.as_ref().unwrap().clone(); 86 vgic.lock().unwrap().set_gicr_typers(vcpu_states); 87 } 88 } 89 90 impl InterruptController for Gic { 91 fn enable(&self) -> Result<()> { 92 // Set irqfd for legacy interrupts 93 self.interrupt_source_group 94 .enable() 95 .map_err(Error::EnableInterrupt)?; 96 97 // Set irq_routing for legacy interrupts. 98 // irqchip: Hardcode to 0 as we support only 1 GIC 99 // pin: Use irq number as pin 100 for i in IRQ_LEGACY_BASE..(IRQ_LEGACY_BASE + IRQ_LEGACY_COUNT) { 101 let config = LegacyIrqSourceConfig { 102 irqchip: 0, 103 pin: (i - IRQ_LEGACY_BASE) as u32, 104 }; 105 self.interrupt_source_group 106 .update( 107 i as InterruptIndex, 108 InterruptSourceConfig::LegacyIrq(config), 109 false, 110 ) 111 .map_err(Error::EnableInterrupt)?; 112 } 113 Ok(()) 114 } 115 116 // This should be called anytime an interrupt needs to be injected into the 117 // running guest. 118 fn service_irq(&mut self, irq: usize) -> Result<()> { 119 self.interrupt_source_group 120 .trigger(irq as InterruptIndex) 121 .map_err(Error::TriggerInterrupt)?; 122 123 Ok(()) 124 } 125 126 fn notifier(&self, irq: usize) -> Option<EventFd> { 127 self.interrupt_source_group.notifier(irq as InterruptIndex) 128 } 129 } 130 131 pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its"; 132 impl Snapshottable for Gic { 133 fn id(&self) -> String { 134 GIC_V3_ITS_SNAPSHOT_ID.to_string() 135 } 136 137 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 138 let vgic = self.vgic.as_ref().unwrap().clone(); 139 let state = vgic.lock().unwrap().state().unwrap(); 140 Snapshot::new_from_state(&self.id(), &state) 141 } 142 143 fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 144 let vgic = self.vgic.as_ref().unwrap().clone(); 145 vgic.lock() 146 .unwrap() 147 .set_state(&snapshot.to_state(&self.id())?) 148 .map_err(|e| { 149 MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e)) 150 })?; 151 Ok(()) 152 } 153 } 154 155 impl Pausable for Gic { 156 fn pause(&mut self) -> std::result::Result<(), MigratableError> { 157 // Flush tables to guest RAM 158 let vgic = self.vgic.as_ref().unwrap().clone(); 159 vgic.lock().unwrap().save_data_tables().map_err(|e| { 160 MigratableError::Pause(anyhow!( 161 "Could not save GICv3ITS GIC pending tables {:?}", 162 e 163 )) 164 })?; 165 Ok(()) 166 } 167 } 168 impl Transportable for Gic {} 169 impl Migratable for Gic {} 170