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