1 // Copyright 2022 Arm Limited (or its affiliates). All rights reserved. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 mod dist_regs; 6 mod icc_regs; 7 mod redist_regs; 8 9 use std::any::Any; 10 11 use dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr}; 12 use icc_regs::{get_icc_regs, set_icc_regs}; 13 use kvm_ioctls::DeviceFd; 14 use redist_regs::{construct_gicr_typers, get_redist_regs, set_redist_regs}; 15 use serde::{Deserialize, Serialize}; 16 17 use crate::arch::aarch64::gic::{Error, Result, Vgic, VgicConfig}; 18 use crate::device::HypervisorDeviceError; 19 use crate::kvm::KvmVm; 20 use crate::{CpuState, Vm}; 21 22 const GITS_CTLR: u32 = 0x0000; 23 const GITS_IIDR: u32 = 0x0004; 24 const GITS_CBASER: u32 = 0x0080; 25 const GITS_CWRITER: u32 = 0x0088; 26 const GITS_CREADR: u32 = 0x0090; 27 const GITS_BASER: u32 = 0x0100; 28 29 fn gicv3_its_attr_set(its_device: &DeviceFd, group: u32, attr: u32, val: u64) -> Result<()> { 30 let gicv3_its_attr = kvm_bindings::kvm_device_attr { 31 group, 32 attr: attr as u64, 33 addr: &val as *const u64 as u64, 34 flags: 0, 35 }; 36 37 its_device 38 .set_device_attr(&gicv3_its_attr) 39 .map_err(|e| Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))) 40 } 41 42 fn gicv3_its_attr_get(its_device: &DeviceFd, group: u32, attr: u32) -> Result<u64> { 43 let mut val = 0; 44 45 let mut gicv3_its_attr = kvm_bindings::kvm_device_attr { 46 group, 47 attr: attr as u64, 48 addr: &mut val as *mut u64 as u64, 49 flags: 0, 50 }; 51 52 // SAFETY: gicv3_its_attr.addr is safe to write to. 53 unsafe { its_device.get_device_attr(&mut gicv3_its_attr) }.map_err(|e| { 54 Error::GetDeviceAttribute(HypervisorDeviceError::GetDeviceAttribute(e.into())) 55 })?; 56 57 Ok(val) 58 } 59 60 /// Function that saves/restores ITS tables into guest RAM. 61 /// 62 /// The tables get flushed to guest RAM whenever the VM gets stopped. 63 pub fn gicv3_its_tables_access(its_device: &DeviceFd, save: bool) -> Result<()> { 64 let attr = if save { 65 u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES) 66 } else { 67 u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES) 68 }; 69 70 let init_gic_attr = kvm_bindings::kvm_device_attr { 71 group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 72 attr, 73 addr: 0, 74 flags: 0, 75 }; 76 its_device 77 .set_device_attr(&init_gic_attr) 78 .map_err(|e| Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into()))) 79 } 80 81 pub struct KvmGicV3Its { 82 /// The KVM device for the GicV3 83 device: DeviceFd, 84 85 /// The KVM device for the Its device 86 its_device: Option<DeviceFd>, 87 88 /// Vector holding values of GICR_TYPER for each vCPU 89 gicr_typers: Vec<u64>, 90 91 /// GIC distributor address 92 dist_addr: u64, 93 94 /// GIC distributor size 95 dist_size: u64, 96 97 /// GIC distributors address 98 redists_addr: u64, 99 100 /// GIC distributors size 101 redists_size: u64, 102 103 /// GIC MSI address 104 msi_addr: u64, 105 106 /// GIC MSI size 107 msi_size: u64, 108 109 /// Number of CPUs handled by the device 110 vcpu_count: u64, 111 } 112 113 #[derive(Clone, Default, Serialize, Deserialize)] 114 pub struct Gicv3ItsState { 115 dist: Vec<u32>, 116 rdist: Vec<u32>, 117 icc: Vec<u32>, 118 // special register that enables interrupts and affinity routing 119 gicd_ctlr: u32, 120 its_ctlr: u64, 121 its_iidr: u64, 122 its_cbaser: u64, 123 its_cwriter: u64, 124 its_creadr: u64, 125 its_baser: [u64; 8], 126 } 127 128 impl KvmGicV3Its { 129 /// Device trees specific constants 130 pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9; 131 132 /// Returns the GIC version of the device 133 fn version() -> u32 { 134 kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3 135 } 136 137 /// Setup the device-specific attributes 138 fn init_device_attributes(&mut self, vm: &KvmVm, nr_irqs: u32) -> Result<()> { 139 // GicV3 part attributes 140 /* Setting up the distributor attribute. */ 141 Self::set_device_attribute( 142 &self.device, 143 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, 144 u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST), 145 &self.dist_addr as *const u64 as u64, 146 0, 147 )?; 148 149 /* Setting up the redistributors' attribute. */ 150 Self::set_device_attribute( 151 &self.device, 152 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, 153 u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST), 154 &self.redists_addr as *const u64 as u64, 155 0, 156 )?; 157 158 // ITS part attributes 159 let mut its_device = kvm_bindings::kvm_create_device { 160 type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS, 161 fd: 0, 162 flags: 0, 163 }; 164 165 let its_fd = vm 166 .create_device(&mut its_device) 167 .map_err(Error::CreateGic)?; 168 169 // We know vm is KvmVm 170 let its_fd = its_fd.to_kvm().unwrap(); 171 172 Self::set_device_attribute( 173 &its_fd, 174 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, 175 u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE), 176 &self.msi_addr as *const u64 as u64, 177 0, 178 )?; 179 180 Self::set_device_attribute( 181 &its_fd, 182 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 183 u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT), 184 0, 185 0, 186 )?; 187 188 self.its_device = Some(its_fd); 189 190 /* We need to tell the kernel how many irqs to support with this vgic. 191 * See the `layout` module for details. 192 */ 193 let nr_irqs_ptr = &nr_irqs as *const u32; 194 Self::set_device_attribute( 195 &self.device, 196 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 197 0, 198 nr_irqs_ptr as u64, 199 0, 200 )?; 201 202 /* Finalize the GIC. 203 * See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211. 204 */ 205 Self::set_device_attribute( 206 &self.device, 207 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 208 u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT), 209 0, 210 0, 211 ) 212 } 213 214 /// Create a KVM Vgic device 215 fn create_device(vm: &KvmVm) -> Result<DeviceFd> { 216 let mut gic_device = kvm_bindings::kvm_create_device { 217 type_: Self::version(), 218 fd: 0, 219 flags: 0, 220 }; 221 222 let device_fd = vm 223 .create_device(&mut gic_device) 224 .map_err(Error::CreateGic)?; 225 226 // We know for sure this is a KVM fd 227 Ok(device_fd.to_kvm().unwrap()) 228 } 229 230 /// Set a GIC device attribute 231 fn set_device_attribute( 232 device: &DeviceFd, 233 group: u32, 234 attr: u64, 235 addr: u64, 236 flags: u32, 237 ) -> Result<()> { 238 let attr = kvm_bindings::kvm_device_attr { 239 flags, 240 group, 241 attr, 242 addr, 243 }; 244 device.set_device_attr(&attr).map_err(|e| { 245 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 246 }) 247 } 248 249 /// Method to initialize the GIC device 250 pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> { 251 // This is inside KVM module 252 let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?"); 253 254 let vgic = Self::create_device(vm)?; 255 256 let mut gic_device = KvmGicV3Its { 257 device: vgic, 258 its_device: None, 259 gicr_typers: vec![0; config.vcpu_count.try_into().unwrap()], 260 dist_addr: config.dist_addr, 261 dist_size: config.dist_size, 262 redists_addr: config.redists_addr, 263 redists_size: config.redists_size, 264 msi_addr: config.msi_addr, 265 msi_size: config.msi_size, 266 vcpu_count: config.vcpu_count, 267 }; 268 269 gic_device.init_device_attributes(vm, config.nr_irqs)?; 270 271 Ok(gic_device) 272 } 273 } 274 275 impl Vgic for KvmGicV3Its { 276 fn fdt_compatibility(&self) -> &str { 277 "arm,gic-v3" 278 } 279 280 fn msi_compatible(&self) -> bool { 281 true 282 } 283 284 fn msi_compatibility(&self) -> &str { 285 "arm,gic-v3-its" 286 } 287 288 fn fdt_maint_irq(&self) -> u32 { 289 KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ 290 } 291 292 fn vcpu_count(&self) -> u64 { 293 self.vcpu_count 294 } 295 296 fn device_properties(&self) -> [u64; 4] { 297 [ 298 self.dist_addr, 299 self.dist_size, 300 self.redists_addr, 301 self.redists_size, 302 ] 303 } 304 305 fn msi_properties(&self) -> [u64; 2] { 306 [self.msi_addr, self.msi_size] 307 } 308 309 fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) { 310 let gicr_typers = construct_gicr_typers(vcpu_states); 311 self.gicr_typers = gicr_typers; 312 } 313 314 fn as_any_concrete_mut(&mut self) -> &mut dyn Any { 315 self 316 } 317 318 /// Save the state of GICv3ITS. 319 fn state(&self) -> Result<Gicv3ItsState> { 320 let gicr_typers = self.gicr_typers.clone(); 321 322 let gicd_ctlr = read_ctlr(&self.device)?; 323 324 let dist_state = get_dist_regs(&self.device)?; 325 326 let rdist_state = get_redist_regs(&self.device, &gicr_typers)?; 327 328 let icc_state = get_icc_regs(&self.device, &gicr_typers)?; 329 330 let mut its_baser_state: [u64; 8] = [0; 8]; 331 for i in 0..8 { 332 its_baser_state[i as usize] = gicv3_its_attr_get( 333 self.its_device.as_ref().unwrap(), 334 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 335 GITS_BASER + i * 8, 336 )?; 337 } 338 339 let its_ctlr_state = gicv3_its_attr_get( 340 self.its_device.as_ref().unwrap(), 341 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 342 GITS_CTLR, 343 )?; 344 345 let its_cbaser_state = gicv3_its_attr_get( 346 self.its_device.as_ref().unwrap(), 347 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 348 GITS_CBASER, 349 )?; 350 351 let its_creadr_state = gicv3_its_attr_get( 352 self.its_device.as_ref().unwrap(), 353 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 354 GITS_CREADR, 355 )?; 356 357 let its_cwriter_state = gicv3_its_attr_get( 358 self.its_device.as_ref().unwrap(), 359 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 360 GITS_CWRITER, 361 )?; 362 363 let its_iidr_state = gicv3_its_attr_get( 364 self.its_device.as_ref().unwrap(), 365 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 366 GITS_IIDR, 367 )?; 368 369 Ok(Gicv3ItsState { 370 dist: dist_state, 371 rdist: rdist_state, 372 icc: icc_state, 373 gicd_ctlr, 374 its_ctlr: its_ctlr_state, 375 its_iidr: its_iidr_state, 376 its_cbaser: its_cbaser_state, 377 its_cwriter: its_cwriter_state, 378 its_creadr: its_creadr_state, 379 its_baser: its_baser_state, 380 }) 381 } 382 383 /// Restore the state of GICv3ITS. 384 fn set_state(&mut self, state: &Gicv3ItsState) -> Result<()> { 385 let gicr_typers = self.gicr_typers.clone(); 386 387 write_ctlr(&self.device, state.gicd_ctlr)?; 388 389 set_dist_regs(&self.device, &state.dist)?; 390 391 set_redist_regs(&self.device, &gicr_typers, &state.rdist)?; 392 393 set_icc_regs(&self.device, &gicr_typers, &state.icc)?; 394 395 //Restore GICv3ITS registers 396 gicv3_its_attr_set( 397 self.its_device.as_ref().unwrap(), 398 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 399 GITS_IIDR, 400 state.its_iidr, 401 )?; 402 403 gicv3_its_attr_set( 404 self.its_device.as_ref().unwrap(), 405 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 406 GITS_CBASER, 407 state.its_cbaser, 408 )?; 409 410 gicv3_its_attr_set( 411 self.its_device.as_ref().unwrap(), 412 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 413 GITS_CREADR, 414 state.its_creadr, 415 )?; 416 417 gicv3_its_attr_set( 418 self.its_device.as_ref().unwrap(), 419 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 420 GITS_CWRITER, 421 state.its_cwriter, 422 )?; 423 424 for i in 0..8 { 425 gicv3_its_attr_set( 426 self.its_device.as_ref().unwrap(), 427 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 428 GITS_BASER + i * 8, 429 state.its_baser[i as usize], 430 )?; 431 } 432 433 // Restore ITS tables 434 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), false)?; 435 436 gicv3_its_attr_set( 437 self.its_device.as_ref().unwrap(), 438 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 439 GITS_CTLR, 440 state.its_ctlr, 441 ) 442 } 443 444 /// Saves GIC internal data tables into RAM, including: 445 /// - RDIST pending tables 446 /// - ITS tables into guest RAM. 447 fn save_data_tables(&self) -> Result<()> { 448 // Flash RDIST pending tables 449 let init_gic_attr = kvm_bindings::kvm_device_attr { 450 group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 451 attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES), 452 addr: 0, 453 flags: 0, 454 }; 455 self.device.set_device_attr(&init_gic_attr).map_err(|e| { 456 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 457 })?; 458 // Flush ITS tables to guest RAM. 459 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), true) 460 } 461 } 462 463 #[cfg(test)] 464 mod tests { 465 use crate::aarch64::gic::{ 466 get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs, 467 }; 468 use crate::arch::aarch64::gic::VgicConfig; 469 use crate::kvm::KvmGicV3Its; 470 471 fn create_test_vgic_config() -> VgicConfig { 472 VgicConfig { 473 vcpu_count: 1, 474 dist_addr: 0x0900_0000 - 0x01_0000, 475 dist_size: 0x01_0000, 476 // dist_addr - redists_size 477 redists_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000, 478 redists_size: 0x02_0000, 479 // redists_addr - msi_size 480 msi_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000 - 0x02_0000, 481 msi_size: 0x02_0000, 482 nr_irqs: 256, 483 } 484 } 485 486 #[test] 487 fn test_create_gic() { 488 let hv = crate::new().unwrap(); 489 let vm = hv.create_vm().unwrap(); 490 491 KvmGicV3Its::new(&*vm, create_test_vgic_config()).unwrap(); 492 } 493 494 #[test] 495 fn test_get_set_dist_regs() { 496 let hv = crate::new().unwrap(); 497 let vm = hv.create_vm().unwrap(); 498 let _ = vm.create_vcpu(0, None).unwrap(); 499 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic"); 500 501 let state = get_dist_regs(&gic.device).unwrap(); 502 assert_eq!(state.len(), 568); 503 504 set_dist_regs(&gic.device, &state).unwrap(); 505 } 506 507 #[test] 508 fn test_get_set_redist_regs() { 509 let hv = crate::new().unwrap(); 510 let vm = hv.create_vm().unwrap(); 511 let _ = vm.create_vcpu(0, None).unwrap(); 512 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic"); 513 514 let gicr_typer = vec![123]; 515 let state = get_redist_regs(&gic.device, &gicr_typer).unwrap(); 516 println!("{}", state.len()); 517 assert!(state.len() == 24); 518 519 set_redist_regs(&gic.device, &gicr_typer, &state).unwrap(); 520 } 521 522 #[test] 523 fn test_get_set_icc_regs() { 524 let hv = crate::new().unwrap(); 525 let vm = hv.create_vm().unwrap(); 526 let _ = vm.create_vcpu(0, None).unwrap(); 527 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic"); 528 529 let gicr_typer = vec![123]; 530 let state = get_icc_regs(&gic.device, &gicr_typer).unwrap(); 531 println!("{}", state.len()); 532 assert!(state.len() == 9); 533 534 set_icc_regs(&gic.device, &gicr_typer, &state).unwrap(); 535 } 536 537 #[test] 538 fn test_save_data_tables() { 539 let hv = crate::new().unwrap(); 540 let vm = hv.create_vm().unwrap(); 541 let _ = vm.create_vcpu(0, None).unwrap(); 542 let gic = vm 543 .create_vgic(create_test_vgic_config()) 544 .expect("Cannot create gic"); 545 546 gic.lock().unwrap().save_data_tables().unwrap(); 547 } 548 } 549