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 kvm_ioctls::DeviceFd; 6 7 use crate::arch::aarch64::gic::{Error, Result}; 8 use crate::device::HypervisorDeviceError; 9 use crate::kvm::kvm_bindings::{ 10 kvm_device_attr, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, 11 KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, 12 KVM_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_SIZE_U64, 13 }; 14 use crate::kvm::{Register, VcpuKvmState}; 15 use crate::CpuState; 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_set(gic: &DeviceFd, offset: u32, typer: u64, val: u32) -> Result<()> { 100 let 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 107 gic.set_device_attr(&gic_redist_attr).map_err(|e| { 108 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 109 })?; 110 111 Ok(()) 112 } 113 114 fn redist_attr_get(gic: &DeviceFd, offset: u32, typer: u64) -> Result<u32> { 115 let mut val = 0; 116 117 let mut gic_redist_attr = kvm_device_attr { 118 group: KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, 119 attr: (typer & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) | (offset as u64), // this needs the mpidr 120 addr: &mut val as *mut u32 as u64, 121 flags: 0, 122 }; 123 124 // SAFETY: gic_redist_attr.addr is safe to write to. 125 unsafe { gic.get_device_attr(&mut gic_redist_attr) }.map_err(|e| { 126 Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into())) 127 })?; 128 129 Ok(val) 130 } 131 132 fn access_redists_aux( 133 gic: &DeviceFd, 134 gicr_typer: &[u64], 135 state: &mut Vec<u32>, 136 reg_list: &[RdistReg], 137 idx: &mut usize, 138 set: bool, 139 ) -> Result<()> { 140 for i in gicr_typer { 141 for rdreg in reg_list { 142 let mut base = rdreg.base; 143 let end = base + rdreg.length as u32; 144 145 while base < end { 146 if set { 147 redist_attr_set(gic, base, *i, state[*idx])?; 148 *idx += 1; 149 } else { 150 state.push(redist_attr_get(gic, base, *i)?); 151 } 152 base += REG_SIZE as u32; 153 } 154 } 155 } 156 Ok(()) 157 } 158 159 /// Get redistributor registers. 160 pub fn get_redist_regs(gic: &DeviceFd, gicr_typer: &[u64]) -> Result<Vec<u32>> { 161 let mut state = Vec::new(); 162 let mut idx: usize = 0; 163 access_redists_aux( 164 gic, 165 gicr_typer, 166 &mut state, 167 VGIC_RDIST_REGS, 168 &mut idx, 169 false, 170 )?; 171 172 access_redists_aux(gic, gicr_typer, &mut state, VGIC_SGI_REGS, &mut idx, false)?; 173 Ok(state) 174 } 175 176 /// Set redistributor registers. 177 pub fn set_redist_regs(gic: &DeviceFd, gicr_typer: &[u64], state: &[u32]) -> Result<()> { 178 let mut idx: usize = 0; 179 let mut mut_state = state.to_owned(); 180 access_redists_aux( 181 gic, 182 gicr_typer, 183 &mut mut_state, 184 VGIC_RDIST_REGS, 185 &mut idx, 186 true, 187 )?; 188 access_redists_aux( 189 gic, 190 gicr_typer, 191 &mut mut_state, 192 VGIC_SGI_REGS, 193 &mut idx, 194 true, 195 ) 196 } 197 198 pub fn construct_gicr_typers(vcpu_states: &[CpuState]) -> Vec<u64> { 199 /* Pre-construct the GICR_TYPER: 200 * For our implementation: 201 * Top 32 bits are the affinity value of the associated CPU 202 * CommonLPIAff == 01 (redistributors with same Aff3 share LPI table) 203 * Processor_Number == CPU index starting from 0 204 * DPGS == 0 (GICR_CTLR.DPG* not supported) 205 * Last == 1 if this is the last redistributor in a series of 206 * contiguous redistributor pages 207 * DirectLPI == 0 (direct injection of LPIs not supported) 208 * VLPIS == 0 (virtual LPIs not supported) 209 * PLPIS == 0 (physical LPIs not supported) 210 */ 211 let mut gicr_typers: Vec<u64> = Vec::new(); 212 for (index, state) in vcpu_states.iter().enumerate() { 213 let state: VcpuKvmState = state.clone().into(); 214 let last = (index == vcpu_states.len() - 1) as u64; 215 // state.sys_regs is a big collection of system registers, including MIPDR_EL1 216 let mpidr: Vec<Register> = state 217 .sys_regs 218 .into_iter() 219 .filter(|reg| reg.id == KVM_ARM64_SYSREG_MPIDR_EL1) 220 .collect(); 221 //calculate affinity 222 let mut cpu_affid = mpidr[0].addr & 1095233437695; 223 cpu_affid = ((cpu_affid & 0xFF00000000) >> 8) | (cpu_affid & 0xFFFFFF); 224 gicr_typers.push((cpu_affid << 32) | (1 << 24) | (index as u64) << 8 | (last << 4)); 225 } 226 227 gicr_typers 228 } 229