1 // Copyright 2022 Arm Limited (or its affiliates). All rights reserved. 2 // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 // SPDX-License-Identifier: Apache-2.0 4 5 use crate::arch::aarch64::gic::{Error, Result}; 6 use crate::device::HypervisorDeviceError; 7 use crate::kvm::kvm_bindings::{ 8 kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, 9 KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, 10 KVM_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_SIZE_U64, 11 }; 12 use crate::kvm::Register; 13 use crate::kvm::VcpuKvmState; 14 use crate::CpuState; 15 use kvm_ioctls::DeviceFd; 16 17 // Relevant redistributor registers that we want to save/restore. 18 const GICR_CTLR: u32 = 0x0000; 19 const GICR_STATUSR: u32 = 0x0010; 20 const GICR_WAKER: u32 = 0x0014; 21 const GICR_PROPBASER: u32 = 0x0070; 22 const GICR_PENDBASER: u32 = 0x0078; 23 24 /* SGI and PPI Redistributor registers, offsets from RD_base */ 25 /* 26 * Redistributor frame offsets from RD_base which is actually SZ_ 27 */ 28 const GICR_SGI_OFFSET: u32 = 0x0001_0000; 29 const GICR_IGROUPR0: u32 = GICR_SGI_OFFSET + 0x0080; 30 const GICR_ICENABLER0: u32 = GICR_SGI_OFFSET + 0x0180; 31 const GICR_ISENABLER0: u32 = GICR_SGI_OFFSET + 0x0100; 32 const GICR_ISPENDR0: u32 = GICR_SGI_OFFSET + 0x0200; 33 const GICR_ICPENDR0: u32 = GICR_SGI_OFFSET + 0x0280; 34 const GICR_ISACTIVER0: u32 = GICR_SGI_OFFSET + 0x0300; 35 const GICR_ICACTIVER0: u32 = GICR_SGI_OFFSET + 0x0380; 36 const GICR_IPRIORITYR0: u32 = GICR_SGI_OFFSET + 0x0400; 37 const GICR_ICFGR0: u32 = GICR_SGI_OFFSET + 0x0C00; 38 39 const KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT: u32 = 32; 40 const KVM_DEV_ARM_VGIC_V3_MPIDR_MASK: u64 = 0xffffffff << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT as u64; 41 42 const KVM_ARM64_SYSREG_MPIDR_EL1: u64 = KVM_REG_ARM64 43 | KVM_REG_SIZE_U64 44 | KVM_REG_ARM64_SYSREG as u64 45 | (((3_u64) << KVM_REG_ARM64_SYSREG_OP0_SHIFT) & KVM_REG_ARM64_SYSREG_OP0_MASK as u64) 46 | (((5_u64) << KVM_REG_ARM64_SYSREG_OP2_SHIFT) & KVM_REG_ARM64_SYSREG_OP2_MASK as u64); 47 48 /// This is how we represent the registers of a distributor. 49 /// It is relevant their offset from the base address of the 50 /// distributor. 51 /// Each register has a different number 52 /// of bits_per_irq and is therefore variable length. 53 /// First 32 interrupts (0-32) are private to each CPU (SGIs and PPIs). 54 /// and so we save the first irq to identify between the type of the interrupt 55 /// that the respective register deals with. 56 struct RdistReg { 57 /// Offset from distributor address. 58 base: u32, 59 /// Length of the register. 60 length: u8, 61 } 62 63 // All or at least the registers we are interested in are 32 bit, so 64 // we use a constant for size(u32). 65 const REG_SIZE: u8 = 4; 66 67 // Creates a vgic redistributor register. 68 macro_rules! VGIC_RDIST_REG { 69 ($base:expr, $len:expr) => { 70 RdistReg { 71 base: $base, 72 length: $len, 73 } 74 }; 75 } 76 77 // List with relevant distributor registers that we will be restoring. 78 static VGIC_RDIST_REGS: &[RdistReg] = &[ 79 VGIC_RDIST_REG!(GICR_STATUSR, 4), 80 VGIC_RDIST_REG!(GICR_WAKER, 4), 81 VGIC_RDIST_REG!(GICR_PROPBASER, 8), 82 VGIC_RDIST_REG!(GICR_PENDBASER, 8), 83 VGIC_RDIST_REG!(GICR_CTLR, 4), 84 ]; 85 86 // List with relevant distributor registers that we will be restoring. 87 static VGIC_SGI_REGS: &[RdistReg] = &[ 88 VGIC_RDIST_REG!(GICR_IGROUPR0, 4), 89 VGIC_RDIST_REG!(GICR_ICENABLER0, 4), 90 VGIC_RDIST_REG!(GICR_ISENABLER0, 4), 91 VGIC_RDIST_REG!(GICR_ICFGR0, 8), 92 VGIC_RDIST_REG!(GICR_ICPENDR0, 4), 93 VGIC_RDIST_REG!(GICR_ISPENDR0, 4), 94 VGIC_RDIST_REG!(GICR_ICACTIVER0, 4), 95 VGIC_RDIST_REG!(GICR_ISACTIVER0, 4), 96 VGIC_RDIST_REG!(GICR_IPRIORITYR0, 32), 97 ]; 98 99 fn redist_attr_access(gic: &DeviceFd, offset: u32, typer: u64, val: &u32, set: bool) -> Result<()> { 100 let mut gic_redist_attr = kvm_device_attr { 101 group: KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, 102 attr: (typer & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) | (offset as u64), // this needs the mpidr 103 addr: val as *const u32 as u64, 104 flags: 0, 105 }; 106 if set { 107 gic.set_device_attr(&gic_redist_attr).map_err(|e| { 108 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 109 })?; 110 } else { 111 gic.get_device_attr(&mut gic_redist_attr).map_err(|e| { 112 Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into())) 113 })?; 114 } 115 Ok(()) 116 } 117 118 fn access_redists_aux( 119 gic: &DeviceFd, 120 gicr_typer: &[u64], 121 state: &mut Vec<u32>, 122 reg_list: &[RdistReg], 123 idx: &mut usize, 124 set: bool, 125 ) -> Result<()> { 126 for i in gicr_typer { 127 for rdreg in reg_list { 128 let mut base = rdreg.base; 129 let end = base + rdreg.length as u32; 130 131 while base < end { 132 let mut val = 0; 133 if set { 134 val = state[*idx]; 135 redist_attr_access(gic, base, *i, &val, true)?; 136 *idx += 1; 137 } else { 138 redist_attr_access(gic, base, *i, &val, false)?; 139 state.push(val); 140 } 141 base += REG_SIZE as u32; 142 } 143 } 144 } 145 Ok(()) 146 } 147 148 /// Get redistributor registers. 149 pub fn get_redist_regs(gic: &DeviceFd, gicr_typer: &[u64]) -> Result<Vec<u32>> { 150 let mut state = Vec::new(); 151 let mut idx: usize = 0; 152 access_redists_aux( 153 gic, 154 gicr_typer, 155 &mut state, 156 VGIC_RDIST_REGS, 157 &mut idx, 158 false, 159 )?; 160 161 access_redists_aux(gic, gicr_typer, &mut state, VGIC_SGI_REGS, &mut idx, false)?; 162 Ok(state) 163 } 164 165 /// Set redistributor registers. 166 pub fn set_redist_regs(gic: &DeviceFd, gicr_typer: &[u64], state: &[u32]) -> Result<()> { 167 let mut idx: usize = 0; 168 let mut mut_state = state.to_owned(); 169 access_redists_aux( 170 gic, 171 gicr_typer, 172 &mut mut_state, 173 VGIC_RDIST_REGS, 174 &mut idx, 175 true, 176 )?; 177 access_redists_aux( 178 gic, 179 gicr_typer, 180 &mut mut_state, 181 VGIC_SGI_REGS, 182 &mut idx, 183 true, 184 ) 185 } 186 187 pub fn construct_gicr_typers(vcpu_states: &[CpuState]) -> Vec<u64> { 188 /* Pre-construct the GICR_TYPER: 189 * For our implementation: 190 * Top 32 bits are the affinity value of the associated CPU 191 * CommonLPIAff == 01 (redistributors with same Aff3 share LPI table) 192 * Processor_Number == CPU index starting from 0 193 * DPGS == 0 (GICR_CTLR.DPG* not supported) 194 * Last == 1 if this is the last redistributor in a series of 195 * contiguous redistributor pages 196 * DirectLPI == 0 (direct injection of LPIs not supported) 197 * VLPIS == 0 (virtual LPIs not supported) 198 * PLPIS == 0 (physical LPIs not supported) 199 */ 200 let mut gicr_typers: Vec<u64> = Vec::new(); 201 for (index, state) in vcpu_states.iter().enumerate() { 202 let state: VcpuKvmState = state.clone().into(); 203 let last = (index == vcpu_states.len() - 1) as u64; 204 // state.sys_regs is a big collection of system registers, including MIPDR_EL1 205 let mpidr: Vec<Register> = state 206 .sys_regs 207 .into_iter() 208 .filter(|reg| reg.id == KVM_ARM64_SYSREG_MPIDR_EL1) 209 .collect(); 210 //calculate affinity 211 let mut cpu_affid = mpidr[0].addr & 1095233437695; 212 cpu_affid = ((cpu_affid & 0xFF00000000) >> 8) | (cpu_affid & 0xFFFFFF); 213 gicr_typers.push((cpu_affid << 32) | (1 << 24) | (index as u64) << 8 | (last << 4)); 214 } 215 216 gicr_typers 217 } 218