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