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