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