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