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::{arch::aarch64::gic::Vgic, CpuState}; 10 use std::result; 11 use std::sync::{Arc, Mutex}; 12 use vm_device::interrupt::{ 13 InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup, 14 LegacyIrqSourceConfig, MsiIrqGroupConfig, 15 }; 16 use vm_memory::Address; 17 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; 18 use vmm_sys_util::eventfd::EventFd; 19 20 type Result<T> = result::Result<T, Error>; 21 22 // Reserve 32 IRQs for legacy devices. 23 pub const IRQ_LEGACY_BASE: usize = layout::IRQ_BASE as usize; 24 pub const IRQ_LEGACY_COUNT: usize = 32; 25 26 // Gic (Generic Interupt Controller) struct provides all the functionality of a 27 // GIC device. It wraps a hypervisor-emulated GIC device (Vgic) provided by the 28 // `hypervisor` crate. 29 // Gic struct also implements InterruptController to provide interrupt delivery 30 // service. 31 pub struct Gic { 32 interrupt_source_group: Arc<dyn InterruptSourceGroup>, 33 // The hypervisor agnostic virtual GIC 34 vgic: Option<Arc<Mutex<dyn Vgic>>>, 35 } 36 37 impl Gic { 38 pub fn new( 39 _vcpu_count: u8, 40 interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>, 41 ) -> Result<Gic> { 42 let interrupt_source_group = interrupt_manager 43 .create_group(MsiIrqGroupConfig { 44 base: IRQ_LEGACY_BASE as InterruptIndex, 45 count: IRQ_LEGACY_COUNT as InterruptIndex, 46 }) 47 .map_err(Error::CreateInterruptSourceGroup)?; 48 49 Ok(Gic { 50 interrupt_source_group, 51 vgic: None, 52 }) 53 } 54 55 pub fn create_vgic( 56 &mut self, 57 vm: &Arc<dyn hypervisor::Vm>, 58 vcpu_count: u64, 59 ) -> Result<Arc<Mutex<dyn Vgic>>> { 60 let vgic = vm 61 .create_vgic( 62 vcpu_count, 63 layout::GIC_V3_DIST_START.raw_value(), 64 layout::GIC_V3_DIST_SIZE, 65 layout::GIC_V3_REDIST_SIZE, 66 layout::GIC_V3_ITS_SIZE, 67 layout::IRQ_NUM, 68 ) 69 .map_err(Error::CreateGic)?; 70 self.vgic = Some(vgic.clone()); 71 Ok(vgic.clone()) 72 } 73 74 pub fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) { 75 let vgic = self.vgic.as_ref().unwrap().clone(); 76 vgic.lock().unwrap().set_gicr_typers(vcpu_states); 77 } 78 } 79 80 impl InterruptController for Gic { 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 ) 101 .map_err(Error::EnableInterrupt)?; 102 } 103 Ok(()) 104 } 105 106 // This should be called anytime an interrupt needs to be injected into the 107 // running guest. 108 fn service_irq(&mut self, irq: usize) -> Result<()> { 109 self.interrupt_source_group 110 .trigger(irq as InterruptIndex) 111 .map_err(Error::TriggerInterrupt)?; 112 113 Ok(()) 114 } 115 116 fn notifier(&self, irq: usize) -> Option<EventFd> { 117 self.interrupt_source_group.notifier(irq as InterruptIndex) 118 } 119 } 120 121 pub const GIC_V3_ITS_SNAPSHOT_ID: &str = "gic-v3-its"; 122 impl Snapshottable for Gic { 123 fn id(&self) -> String { 124 GIC_V3_ITS_SNAPSHOT_ID.to_string() 125 } 126 127 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 128 let vgic = self.vgic.as_ref().unwrap().clone(); 129 let state = vgic.lock().unwrap().state().unwrap(); 130 Snapshot::new_from_state(&self.id(), &state) 131 } 132 133 fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 134 let vgic = self.vgic.as_ref().unwrap().clone(); 135 vgic.lock() 136 .unwrap() 137 .set_state(&snapshot.to_state(&self.id())?) 138 .map_err(|e| { 139 MigratableError::Restore(anyhow!("Could not restore GICv3ITS state {:?}", e)) 140 })?; 141 Ok(()) 142 } 143 } 144 145 impl Pausable for Gic { 146 fn pause(&mut self) -> std::result::Result<(), MigratableError> { 147 // Flush tables to guest RAM 148 let vgic = self.vgic.as_ref().unwrap().clone(); 149 vgic.lock().unwrap().save_data_tables().map_err(|e| { 150 MigratableError::Pause(anyhow!( 151 "Could not save GICv3ITS GIC pending tables {:?}", 152 e 153 )) 154 })?; 155 Ok(()) 156 } 157 } 158 impl Transportable for Gic {} 159 impl Migratable for Gic {} 160