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}; 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 We are placing the GIC below 1GB so we need to substract the size of the distributor. 138 */ 139 Self::set_device_attribute( 140 &self.device, 141 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, 142 u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST), 143 &self.dist_addr as *const u64 as u64, 144 0, 145 )?; 146 147 /* Setting up the redistributors' attribute. 148 We are calculating here the start of the redistributors address. We have one per CPU. 149 */ 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 #[allow(clippy::new_ret_no_self)] 251 pub fn new( 252 vm: &dyn Vm, 253 vcpu_count: u64, 254 dist_addr: u64, 255 dist_size: u64, 256 redist_size: u64, 257 msi_size: u64, 258 nr_irqs: u32, 259 ) -> Result<KvmGicV3Its> { 260 // This is inside KVM module 261 let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?"); 262 263 let vgic = Self::create_device(vm)?; 264 let redists_size: u64 = redist_size * vcpu_count; 265 let redists_addr: u64 = dist_addr - redists_size; 266 let msi_addr: u64 = redists_addr - msi_size; 267 268 let mut gic_device = KvmGicV3Its { 269 device: vgic, 270 its_device: None, 271 gicr_typers: vec![0; vcpu_count.try_into().unwrap()], 272 dist_addr, 273 dist_size, 274 redists_addr, 275 redists_size, 276 msi_addr, 277 msi_size, 278 vcpu_count, 279 }; 280 281 gic_device.init_device_attributes(vm, nr_irqs)?; 282 283 Ok(gic_device) 284 } 285 } 286 287 impl Vgic for KvmGicV3Its { 288 fn fdt_compatibility(&self) -> &str { 289 "arm,gic-v3" 290 } 291 292 fn msi_compatible(&self) -> bool { 293 true 294 } 295 296 fn msi_compatibility(&self) -> &str { 297 "arm,gic-v3-its" 298 } 299 300 fn fdt_maint_irq(&self) -> u32 { 301 KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ 302 } 303 304 fn vcpu_count(&self) -> u64 { 305 self.vcpu_count 306 } 307 308 fn device_properties(&self) -> [u64; 4] { 309 [ 310 self.dist_addr, 311 self.dist_size, 312 self.redists_addr, 313 self.redists_size, 314 ] 315 } 316 317 fn msi_properties(&self) -> [u64; 2] { 318 [self.msi_addr, self.msi_size] 319 } 320 321 fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) { 322 let gicr_typers = construct_gicr_typers(vcpu_states); 323 self.gicr_typers = gicr_typers; 324 } 325 326 fn as_any_concrete_mut(&mut self) -> &mut dyn Any { 327 self 328 } 329 330 /// Save the state of GICv3ITS. 331 fn state(&self) -> Result<Gicv3ItsState> { 332 let gicr_typers = self.gicr_typers.clone(); 333 334 let gicd_ctlr = read_ctlr(&self.device)?; 335 336 let dist_state = get_dist_regs(&self.device)?; 337 338 let rdist_state = get_redist_regs(&self.device, &gicr_typers)?; 339 340 let icc_state = get_icc_regs(&self.device, &gicr_typers)?; 341 342 let its_baser_state: [u64; 8] = [0; 8]; 343 for i in 0..8 { 344 gicv3_its_attr_access( 345 self.its_device.as_ref().unwrap(), 346 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 347 GITS_BASER + i * 8, 348 &its_baser_state[i as usize], 349 false, 350 )?; 351 } 352 353 let its_ctlr_state: u64 = 0; 354 gicv3_its_attr_access( 355 self.its_device.as_ref().unwrap(), 356 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 357 GITS_CTLR, 358 &its_ctlr_state, 359 false, 360 )?; 361 362 let its_cbaser_state: u64 = 0; 363 gicv3_its_attr_access( 364 self.its_device.as_ref().unwrap(), 365 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 366 GITS_CBASER, 367 &its_cbaser_state, 368 false, 369 )?; 370 371 let its_creadr_state: u64 = 0; 372 gicv3_its_attr_access( 373 self.its_device.as_ref().unwrap(), 374 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 375 GITS_CREADR, 376 &its_creadr_state, 377 false, 378 )?; 379 380 let its_cwriter_state: u64 = 0; 381 gicv3_its_attr_access( 382 self.its_device.as_ref().unwrap(), 383 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 384 GITS_CWRITER, 385 &its_cwriter_state, 386 false, 387 )?; 388 389 let its_iidr_state: u64 = 0; 390 gicv3_its_attr_access( 391 self.its_device.as_ref().unwrap(), 392 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 393 GITS_IIDR, 394 &its_iidr_state, 395 false, 396 )?; 397 398 Ok(Gicv3ItsState { 399 dist: dist_state, 400 rdist: rdist_state, 401 icc: icc_state, 402 gicd_ctlr, 403 its_ctlr: its_ctlr_state, 404 its_iidr: its_iidr_state, 405 its_cbaser: its_cbaser_state, 406 its_cwriter: its_cwriter_state, 407 its_creadr: its_creadr_state, 408 its_baser: its_baser_state, 409 }) 410 } 411 412 /// Restore the state of GICv3ITS. 413 fn set_state(&mut self, state: &Gicv3ItsState) -> Result<()> { 414 let gicr_typers = self.gicr_typers.clone(); 415 416 write_ctlr(&self.device, state.gicd_ctlr)?; 417 418 set_dist_regs(&self.device, &state.dist)?; 419 420 set_redist_regs(&self.device, &gicr_typers, &state.rdist)?; 421 422 set_icc_regs(&self.device, &gicr_typers, &state.icc)?; 423 424 //Restore GICv3ITS registers 425 gicv3_its_attr_access( 426 self.its_device.as_ref().unwrap(), 427 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 428 GITS_IIDR, 429 &state.its_iidr, 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_CBASER, 437 &state.its_cbaser, 438 true, 439 )?; 440 441 gicv3_its_attr_access( 442 self.its_device.as_ref().unwrap(), 443 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 444 GITS_CREADR, 445 &state.its_creadr, 446 true, 447 )?; 448 449 gicv3_its_attr_access( 450 self.its_device.as_ref().unwrap(), 451 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 452 GITS_CWRITER, 453 &state.its_cwriter, 454 true, 455 )?; 456 457 for i in 0..8 { 458 gicv3_its_attr_access( 459 self.its_device.as_ref().unwrap(), 460 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 461 GITS_BASER + i * 8, 462 &state.its_baser[i as usize], 463 true, 464 )?; 465 } 466 467 // Restore ITS tables 468 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), false)?; 469 470 gicv3_its_attr_access( 471 self.its_device.as_ref().unwrap(), 472 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 473 GITS_CTLR, 474 &state.its_ctlr, 475 true, 476 ) 477 } 478 479 /// Saves GIC internal data tables into RAM, including: 480 /// - RDIST pending tables 481 /// - ITS tables into guest RAM. 482 fn save_data_tables(&self) -> Result<()> { 483 // Flash RDIST pending tables 484 let init_gic_attr = kvm_bindings::kvm_device_attr { 485 group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 486 attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES), 487 addr: 0, 488 flags: 0, 489 }; 490 self.device.set_device_attr(&init_gic_attr).map_err(|e| { 491 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 492 })?; 493 // Flush ITS tables to guest RAM. 494 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), true) 495 } 496 } 497 498 #[cfg(test)] 499 mod tests { 500 use crate::aarch64::gic::{ 501 get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs, 502 }; 503 use crate::kvm::KvmGicV3Its; 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( 511 &*vm, 512 1, 513 0x0900_0000 - 0x01_0000, 514 0x01_0000, 515 0x02_0000, 516 0x02_0000, 517 256 518 ) 519 .is_ok()); 520 } 521 522 #[test] 523 fn test_get_set_dist_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( 528 &*vm, 529 1, 530 0x0900_0000 - 0x01_0000, 531 0x01_0000, 532 0x02_0000, 533 0x02_0000, 534 256, 535 ) 536 .expect("Cannot create gic"); 537 538 let res = get_dist_regs(&gic.device); 539 assert!(res.is_ok()); 540 let state = res.unwrap(); 541 assert_eq!(state.len(), 568); 542 543 let res = set_dist_regs(&gic.device, &state); 544 assert!(res.is_ok()); 545 } 546 547 #[test] 548 fn test_get_set_redist_regs() { 549 let hv = crate::new().unwrap(); 550 let vm = hv.create_vm().unwrap(); 551 let _ = vm.create_vcpu(0, None).unwrap(); 552 let gic = KvmGicV3Its::new( 553 &*vm, 554 1, 555 0x0900_0000 - 0x01_0000, 556 0x01_0000, 557 0x02_0000, 558 0x02_0000, 559 256, 560 ) 561 .expect("Cannot create gic"); 562 563 let gicr_typer = vec![123]; 564 let res = get_redist_regs(&gic.device, &gicr_typer); 565 assert!(res.is_ok()); 566 let state = res.unwrap(); 567 println!("{}", state.len()); 568 assert!(state.len() == 24); 569 570 assert!(set_redist_regs(&gic.device, &gicr_typer, &state).is_ok()); 571 } 572 573 #[test] 574 fn test_get_set_icc_regs() { 575 let hv = crate::new().unwrap(); 576 let vm = hv.create_vm().unwrap(); 577 let _ = vm.create_vcpu(0, None).unwrap(); 578 let gic = KvmGicV3Its::new( 579 &*vm, 580 1, 581 0x0900_0000 - 0x01_0000, 582 0x01_0000, 583 0x02_0000, 584 0x02_0000, 585 256, 586 ) 587 .expect("Cannot create gic"); 588 589 let gicr_typer = vec![123]; 590 let res = get_icc_regs(&gic.device, &gicr_typer); 591 assert!(res.is_ok()); 592 let state = res.unwrap(); 593 println!("{}", state.len()); 594 assert!(state.len() == 9); 595 596 assert!(set_icc_regs(&gic.device, &gicr_typer, &state).is_ok()); 597 } 598 599 #[test] 600 fn test_save_data_tables() { 601 let hv = crate::new().unwrap(); 602 let vm = hv.create_vm().unwrap(); 603 let _ = vm.create_vcpu(0, None).unwrap(); 604 let gic = vm 605 .create_vgic( 606 1, 607 0x0900_0000 - 0x01_0000, 608 0x01_0000, 609 0x02_0000, 610 0x02_0000, 611 256, 612 ) 613 .expect("Cannot create gic"); 614 615 assert!(gic.lock().unwrap().save_data_tables().is_ok()); 616 } 617 } 618