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 } 133 } 134 } 135 136 impl From<Gicv3ItsState> for GicState { 137 fn from(state: Gicv3ItsState) -> Self { 138 GicState::Kvm(state) 139 } 140 } 141 142 impl KvmGicV3Its { 143 /// Device trees specific constants 144 pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9; 145 146 /// Returns the GIC version of the device 147 fn version() -> u32 { 148 kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3 149 } 150 151 /// Setup the device-specific attributes 152 fn init_device_attributes(&mut self, vm: &KvmVm, nr_irqs: u32) -> Result<()> { 153 // GicV3 part attributes 154 /* Setting up the distributor attribute. */ 155 Self::set_device_attribute( 156 &self.device, 157 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, 158 u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST), 159 &self.dist_addr as *const u64 as u64, 160 0, 161 )?; 162 163 /* Setting up the redistributors' attribute. */ 164 Self::set_device_attribute( 165 &self.device, 166 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, 167 u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST), 168 &self.redists_addr as *const u64 as u64, 169 0, 170 )?; 171 172 // ITS part attributes 173 let mut its_device = kvm_bindings::kvm_create_device { 174 type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS, 175 fd: 0, 176 flags: 0, 177 }; 178 179 let its_fd = vm 180 .create_device(&mut its_device) 181 .map_err(Error::CreateGic)?; 182 183 // We know vm is KvmVm 184 let its_fd = its_fd.to_kvm().unwrap(); 185 186 Self::set_device_attribute( 187 &its_fd, 188 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, 189 u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE), 190 &self.msi_addr as *const u64 as u64, 191 0, 192 )?; 193 194 Self::set_device_attribute( 195 &its_fd, 196 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 197 u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT), 198 0, 199 0, 200 )?; 201 202 self.its_device = Some(its_fd); 203 204 /* We need to tell the kernel how many irqs to support with this vgic. 205 * See the `layout` module for details. 206 */ 207 let nr_irqs_ptr = &nr_irqs as *const u32; 208 Self::set_device_attribute( 209 &self.device, 210 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 211 0, 212 nr_irqs_ptr as u64, 213 0, 214 )?; 215 216 /* Finalize the GIC. 217 * See https://code.woboq.org/linux/linux/virt/kvm/arm/vgic/vgic-kvm-device.c.html#211. 218 */ 219 Self::set_device_attribute( 220 &self.device, 221 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 222 u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CTRL_INIT), 223 0, 224 0, 225 ) 226 } 227 228 /// Create a KVM Vgic device 229 fn create_device(vm: &KvmVm) -> Result<DeviceFd> { 230 let mut gic_device = kvm_bindings::kvm_create_device { 231 type_: Self::version(), 232 fd: 0, 233 flags: 0, 234 }; 235 236 let device_fd = vm 237 .create_device(&mut gic_device) 238 .map_err(Error::CreateGic)?; 239 240 // We know for sure this is a KVM fd 241 Ok(device_fd.to_kvm().unwrap()) 242 } 243 244 /// Set a GIC device attribute 245 fn set_device_attribute( 246 device: &DeviceFd, 247 group: u32, 248 attr: u64, 249 addr: u64, 250 flags: u32, 251 ) -> Result<()> { 252 let attr = kvm_bindings::kvm_device_attr { 253 flags, 254 group, 255 attr, 256 addr, 257 }; 258 device.set_device_attr(&attr).map_err(|e| { 259 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 260 }) 261 } 262 263 /// Method to initialize the GIC device 264 pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> { 265 // This is inside KVM module 266 let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?"); 267 268 let vgic = Self::create_device(vm)?; 269 270 let mut gic_device = KvmGicV3Its { 271 device: vgic, 272 its_device: None, 273 gicr_typers: vec![0; config.vcpu_count.try_into().unwrap()], 274 dist_addr: config.dist_addr, 275 dist_size: config.dist_size, 276 redists_addr: config.redists_addr, 277 redists_size: config.redists_size, 278 msi_addr: config.msi_addr, 279 msi_size: config.msi_size, 280 vcpu_count: config.vcpu_count, 281 }; 282 283 gic_device.init_device_attributes(vm, config.nr_irqs)?; 284 285 Ok(gic_device) 286 } 287 } 288 289 impl Vgic for KvmGicV3Its { 290 fn fdt_compatibility(&self) -> &str { 291 "arm,gic-v3" 292 } 293 294 fn msi_compatible(&self) -> bool { 295 true 296 } 297 298 fn msi_compatibility(&self) -> &str { 299 "arm,gic-v3-its" 300 } 301 302 fn fdt_maint_irq(&self) -> u32 { 303 KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ 304 } 305 306 fn vcpu_count(&self) -> u64 { 307 self.vcpu_count 308 } 309 310 fn device_properties(&self) -> [u64; 4] { 311 [ 312 self.dist_addr, 313 self.dist_size, 314 self.redists_addr, 315 self.redists_size, 316 ] 317 } 318 319 fn msi_properties(&self) -> [u64; 2] { 320 [self.msi_addr, self.msi_size] 321 } 322 323 fn set_gicr_typers(&mut self, vcpu_states: &[CpuState]) { 324 let gicr_typers = construct_gicr_typers(vcpu_states); 325 self.gicr_typers = gicr_typers; 326 } 327 328 fn as_any_concrete_mut(&mut self) -> &mut dyn Any { 329 self 330 } 331 332 /// Save the state of GICv3ITS. 333 fn state(&self) -> Result<GicState> { 334 let gicr_typers = self.gicr_typers.clone(); 335 336 let gicd_ctlr = read_ctlr(&self.device)?; 337 338 let dist_state = get_dist_regs(&self.device)?; 339 340 let rdist_state = get_redist_regs(&self.device, &gicr_typers)?; 341 342 let icc_state = get_icc_regs(&self.device, &gicr_typers)?; 343 344 let mut its_baser_state: [u64; 8] = [0; 8]; 345 for i in 0..8 { 346 its_baser_state[i as usize] = gicv3_its_attr_get( 347 self.its_device.as_ref().unwrap(), 348 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 349 GITS_BASER + i * 8, 350 )?; 351 } 352 353 let its_ctlr_state = gicv3_its_attr_get( 354 self.its_device.as_ref().unwrap(), 355 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 356 GITS_CTLR, 357 )?; 358 359 let its_cbaser_state = gicv3_its_attr_get( 360 self.its_device.as_ref().unwrap(), 361 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 362 GITS_CBASER, 363 )?; 364 365 let its_creadr_state = gicv3_its_attr_get( 366 self.its_device.as_ref().unwrap(), 367 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 368 GITS_CREADR, 369 )?; 370 371 let its_cwriter_state = gicv3_its_attr_get( 372 self.its_device.as_ref().unwrap(), 373 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 374 GITS_CWRITER, 375 )?; 376 377 let its_iidr_state = gicv3_its_attr_get( 378 self.its_device.as_ref().unwrap(), 379 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 380 GITS_IIDR, 381 )?; 382 383 let gic_state: GicState = 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 .into(); 396 397 Ok(gic_state) 398 } 399 400 /// Restore the state of GICv3ITS. 401 fn set_state(&mut self, state: &GicState) -> Result<()> { 402 let kvm_state: Gicv3ItsState = state.clone().into(); 403 404 let gicr_typers = self.gicr_typers.clone(); 405 406 write_ctlr(&self.device, kvm_state.gicd_ctlr)?; 407 408 set_dist_regs(&self.device, &kvm_state.dist)?; 409 410 set_redist_regs(&self.device, &gicr_typers, &kvm_state.rdist)?; 411 412 set_icc_regs(&self.device, &gicr_typers, &kvm_state.icc)?; 413 414 //Restore GICv3ITS registers 415 gicv3_its_attr_set( 416 self.its_device.as_ref().unwrap(), 417 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 418 GITS_IIDR, 419 kvm_state.its_iidr, 420 )?; 421 422 gicv3_its_attr_set( 423 self.its_device.as_ref().unwrap(), 424 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 425 GITS_CBASER, 426 kvm_state.its_cbaser, 427 )?; 428 429 gicv3_its_attr_set( 430 self.its_device.as_ref().unwrap(), 431 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 432 GITS_CREADR, 433 kvm_state.its_creadr, 434 )?; 435 436 gicv3_its_attr_set( 437 self.its_device.as_ref().unwrap(), 438 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 439 GITS_CWRITER, 440 kvm_state.its_cwriter, 441 )?; 442 443 for i in 0..8 { 444 gicv3_its_attr_set( 445 self.its_device.as_ref().unwrap(), 446 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 447 GITS_BASER + i * 8, 448 kvm_state.its_baser[i as usize], 449 )?; 450 } 451 452 // Restore ITS tables 453 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), false)?; 454 455 gicv3_its_attr_set( 456 self.its_device.as_ref().unwrap(), 457 kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, 458 GITS_CTLR, 459 kvm_state.its_ctlr, 460 ) 461 } 462 463 /// Saves GIC internal data tables into RAM, including: 464 /// - RDIST pending tables 465 /// - ITS tables into guest RAM. 466 fn save_data_tables(&self) -> Result<()> { 467 // Flash RDIST pending tables 468 let init_gic_attr = kvm_bindings::kvm_device_attr { 469 group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, 470 attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES), 471 addr: 0, 472 flags: 0, 473 }; 474 self.device.set_device_attr(&init_gic_attr).map_err(|e| { 475 Error::SetDeviceAttribute(HypervisorDeviceError::SetDeviceAttribute(e.into())) 476 })?; 477 // Flush ITS tables to guest RAM. 478 gicv3_its_tables_access(self.its_device.as_ref().unwrap(), true) 479 } 480 } 481 482 #[cfg(test)] 483 mod tests { 484 use crate::aarch64::gic::{ 485 get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs, 486 }; 487 use crate::arch::aarch64::gic::VgicConfig; 488 use crate::kvm::KvmGicV3Its; 489 490 fn create_test_vgic_config() -> VgicConfig { 491 VgicConfig { 492 vcpu_count: 1, 493 dist_addr: 0x0900_0000 - 0x01_0000, 494 dist_size: 0x01_0000, 495 // dist_addr - redists_size 496 redists_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000, 497 redists_size: 0x02_0000, 498 // redists_addr - msi_size 499 msi_addr: 0x0900_0000 - 0x01_0000 - 0x02_0000 - 0x02_0000, 500 msi_size: 0x02_0000, 501 nr_irqs: 256, 502 } 503 } 504 505 #[test] 506 fn test_create_gic() { 507 let hv = crate::new().unwrap(); 508 let vm = hv.create_vm().unwrap(); 509 510 KvmGicV3Its::new(&*vm, create_test_vgic_config()).unwrap(); 511 } 512 513 #[test] 514 fn test_get_set_dist_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 state = get_dist_regs(&gic.device).unwrap(); 521 assert_eq!(state.len(), 568); 522 523 set_dist_regs(&gic.device, &state).unwrap(); 524 } 525 526 #[test] 527 fn test_get_set_redist_regs() { 528 let hv = crate::new().unwrap(); 529 let vm = hv.create_vm().unwrap(); 530 let _ = vm.create_vcpu(0, None).unwrap(); 531 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic"); 532 533 let gicr_typer = vec![123]; 534 let state = get_redist_regs(&gic.device, &gicr_typer).unwrap(); 535 println!("{}", state.len()); 536 assert!(state.len() == 24); 537 538 set_redist_regs(&gic.device, &gicr_typer, &state).unwrap(); 539 } 540 541 #[test] 542 fn test_get_set_icc_regs() { 543 let hv = crate::new().unwrap(); 544 let vm = hv.create_vm().unwrap(); 545 let _ = vm.create_vcpu(0, None).unwrap(); 546 let gic = KvmGicV3Its::new(&*vm, create_test_vgic_config()).expect("Cannot create gic"); 547 548 let gicr_typer = vec![123]; 549 let state = get_icc_regs(&gic.device, &gicr_typer).unwrap(); 550 println!("{}", state.len()); 551 assert!(state.len() == 9); 552 553 set_icc_regs(&gic.device, &gicr_typer, &state).unwrap(); 554 } 555 556 #[test] 557 fn test_save_data_tables() { 558 let hv = crate::new().unwrap(); 559 let vm = hv.create_vm().unwrap(); 560 let _ = vm.create_vcpu(0, None).unwrap(); 561 let gic = vm 562 .create_vgic(create_test_vgic_config()) 563 .expect("Cannot create gic"); 564 565 gic.lock().unwrap().save_data_tables().unwrap(); 566 } 567 } 568