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