@@ -891,6 +891,74 @@ impl VmFd {
891
891
}
892
892
}
893
893
894
+ /// Sets the level on the given irq to 1 if `active` is true, and 0 otherwise.
895
+ ///
896
+ /// # Arguments
897
+ ///
898
+ /// * `irq` - IRQ to be set.
899
+ /// * `active` - Level of the IRQ input.
900
+ ///
901
+ /// # Errors
902
+ ///
903
+ /// Returns an io::Error when the irq field is invalid
904
+ ///
905
+ /// # Examples
906
+ ///
907
+ /// ```rust
908
+ /// # extern crate kvm_ioctls;
909
+ /// # extern crate libc;
910
+ /// # extern crate vmm_sys_util;
911
+ /// # use kvm_ioctls::{Kvm, VmFd};
912
+ /// # use libc::EFD_NONBLOCK;
913
+ /// # use vmm_sys_util::eventfd::EventFd;
914
+ /// fn arch_setup(vm_fd: &VmFd) {
915
+ /// // Arch-specific setup:
916
+ /// // For x86 architectures, it simply means calling vm.create_irq_chip().unwrap().
917
+ /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
918
+ /// # vm_fd.create_irq_chip().unwrap();
919
+ /// // For Arm architectures, the IRQ controllers need to be setup first.
920
+ /// // Details please refer to the kernel documentation.
921
+ /// // https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt
922
+ /// # #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] {
923
+ /// # vm_fd.create_vcpu(0).unwrap();
924
+ /// # // ... rest of setup for Arm goes here
925
+ /// # }
926
+ /// }
927
+ ///
928
+ /// let kvm = Kvm::new().unwrap();
929
+ /// let vm = kvm.create_vm().unwrap();
930
+ /// arch_setup(&vm);
931
+ /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
932
+ /// vm.set_irq_line(4, true);
933
+ /// // ...
934
+ /// }
935
+ /// #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] {
936
+ /// vm.set_irq_line(0x01_00_0020, true);
937
+ /// // ....
938
+ /// }
939
+ /// ```
940
+ ///
941
+ #[ cfg( any(
942
+ target_arch = "x86" ,
943
+ target_arch = "x86_64" ,
944
+ target_arch = "arm" ,
945
+ target_arch = "aarch64"
946
+ ) ) ]
947
+ pub fn set_irq_line ( & self , irq : u32 , active : bool ) -> Result < ( ) > {
948
+ let mut irq_level = kvm_irq_level:: default ( ) ;
949
+ irq_level. __bindgen_anon_1 . irq = irq;
950
+ irq_level. level = if active { 1 } else { 0 } ;
951
+
952
+ // Safe because we know that our file is a VM fd, we know the kernel will only read the
953
+ // correct amount of memory from our pointer, and we verify the return result.
954
+ let ret = unsafe { ioctl_with_ref ( self , KVM_IRQ_LINE ( ) , & irq_level) } ;
955
+ if ret == 0 {
956
+ Ok ( ( ) )
957
+ } else {
958
+ Err ( errno:: Error :: last ( ) )
959
+ }
960
+ }
961
+
894
962
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding
895
963
/// its `kvm_run` structure.
896
964
///
@@ -1119,7 +1187,7 @@ impl AsRawFd for VmFd {
1119
1187
}
1120
1188
}
1121
1189
1122
- /// Creates a dummy GIC device.
1190
+ /// Create a dummy GIC device.
1123
1191
///
1124
1192
/// # Arguments
1125
1193
///
@@ -1145,6 +1213,43 @@ pub(crate) fn create_gic_device(vm: &VmFd, flags: u32) -> DeviceFd {
1145
1213
device_fd
1146
1214
}
1147
1215
1216
+ /// Set supported number of IRQs for vGIC.
1217
+ ///
1218
+ /// # Arguments
1219
+ ///
1220
+ /// * `vgic` - The vGIC file descriptor.
1221
+ /// * `nr_irqs` - Number of IRQs.
1222
+ ///
1223
+ #[ cfg( test) ]
1224
+ #[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
1225
+ pub ( crate ) fn set_supported_nr_irqs ( vgic : & DeviceFd , nr_irqs : u32 ) {
1226
+ let vgic_attr = kvm_bindings:: kvm_device_attr {
1227
+ group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_NR_IRQS ,
1228
+ attr : 0 ,
1229
+ addr : & nr_irqs as * const u32 as u64 ,
1230
+ flags : 0 ,
1231
+ } ;
1232
+ assert ! ( vgic. set_device_attr( & vgic_attr) . is_ok( ) ) ;
1233
+ }
1234
+
1235
+ /// Request the initialization of the vGIC.
1236
+ ///
1237
+ /// # Arguments
1238
+ ///
1239
+ /// * `vgic` - The vGIC file descriptor.
1240
+ ///
1241
+ #[ cfg( test) ]
1242
+ #[ cfg( any( target_arch = "arm" , target_arch = "aarch64" ) ) ]
1243
+ pub ( crate ) fn request_gic_init ( vgic : & DeviceFd ) {
1244
+ let vgic_attr = kvm_bindings:: kvm_device_attr {
1245
+ group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
1246
+ attr : u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_CTRL_INIT ) ,
1247
+ addr : 0 ,
1248
+ flags : 0 ,
1249
+ } ;
1250
+ assert ! ( vgic. set_device_attr( & vgic_attr) . is_ok( ) ) ;
1251
+ }
1252
+
1148
1253
#[ cfg( test) ]
1149
1254
mod tests {
1150
1255
use super :: * ;
@@ -1356,26 +1461,10 @@ mod tests {
1356
1461
// Create the vGIC device.
1357
1462
let vgic_fd = create_gic_device ( & vm_fd, 0 ) ;
1358
1463
1359
- // Dummy interrupt for testing on aarch64.
1360
- let nr_irqs: u32 = 128 ;
1361
-
1362
- // We need to tell the kernel how many irqs to support with this vgic.
1363
- let vgic_attr = kvm_bindings:: kvm_device_attr {
1364
- group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_NR_IRQS ,
1365
- attr : 0 ,
1366
- addr : & nr_irqs as * const u32 as u64 ,
1367
- flags : 0 ,
1368
- } ;
1369
- assert ! ( vgic_fd. set_device_attr( & vgic_attr) . is_ok( ) ) ;
1370
-
1371
- // Finalize the GIC.
1372
- let vgic_attr = kvm_bindings:: kvm_device_attr {
1373
- group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
1374
- attr : u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_CTRL_INIT ) ,
1375
- addr : 0 ,
1376
- flags : 0 ,
1377
- } ;
1378
- assert ! ( vgic_fd. set_device_attr( & vgic_attr) . is_ok( ) ) ;
1464
+ // Set supported number of IRQs.
1465
+ set_supported_nr_irqs ( & vgic_fd, 128 ) ;
1466
+ // Request the initialization of the vGIC.
1467
+ request_gic_init ( & vgic_fd) ;
1379
1468
1380
1469
assert ! ( vm_fd. register_irqfd( & evtfd1, 4 ) . is_ok( ) ) ;
1381
1470
assert ! ( vm_fd. register_irqfd( & evtfd2, 8 ) . is_ok( ) ) ;
@@ -1393,6 +1482,52 @@ mod tests {
1393
1482
assert ! ( vm_fd. unregister_irqfd( & evtfd3, 5 ) . is_ok( ) ) ;
1394
1483
}
1395
1484
1485
+ #[ test]
1486
+ #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
1487
+ fn test_set_irq_line ( ) {
1488
+ let kvm = Kvm :: new ( ) . unwrap ( ) ;
1489
+ let vm_fd = kvm. create_vm ( ) . unwrap ( ) ;
1490
+
1491
+ assert ! ( vm_fd. create_irq_chip( ) . is_ok( ) ) ;
1492
+
1493
+ assert ! ( vm_fd. set_irq_line( 4 , true ) . is_ok( ) ) ;
1494
+ assert ! ( vm_fd. set_irq_line( 4 , false ) . is_ok( ) ) ;
1495
+ assert ! ( vm_fd. set_irq_line( 4 , true ) . is_ok( ) ) ;
1496
+ }
1497
+
1498
+ #[ test]
1499
+ #[ cfg( target_arch = "aarch64" ) ]
1500
+ fn test_set_irq_line ( ) {
1501
+ let kvm = Kvm :: new ( ) . unwrap ( ) ;
1502
+ let vm_fd = kvm. create_vm ( ) . unwrap ( ) ;
1503
+ // Create a vcpu for test case 2 of the KVM_IRQ_LINE API on aarch64.
1504
+ vm_fd. create_vcpu ( 0 ) . unwrap ( ) ;
1505
+
1506
+ // Create the vGIC device.
1507
+ let vgic_fd = create_gic_device ( & vm_fd, 0 ) ;
1508
+ // Set supported number of IRQs.
1509
+ set_supported_nr_irqs ( & vgic_fd, 128 ) ;
1510
+ // Request the initialization of the vGIC.
1511
+ request_gic_init ( & vgic_fd) ;
1512
+
1513
+ // On arm/aarch64, irq field is interpreted like this:
1514
+ // bits: | 31 ... 24 | 23 ... 16 | 15 ... 0 |
1515
+ // field: | irq_type | vcpu_index | irq_id |
1516
+ // The irq_type field has the following values:
1517
+ // - irq_type[0]: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ
1518
+ // - irq_type[1]: in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.) (the vcpu_index field is ignored)
1519
+ // - irq_type[2]: in-kernel GIC: PPI, irq_id between 16 and 31 (incl.)
1520
+ // Hence, using irq_type = 1, irq_id = 32 (decimal), the irq field in hex is: 0x01_00_0020
1521
+ assert ! ( vm_fd. set_irq_line( 0x01_00_0020 , true ) . is_ok( ) ) ;
1522
+ assert ! ( vm_fd. set_irq_line( 0x01_00_0020 , false ) . is_ok( ) ) ;
1523
+ assert ! ( vm_fd. set_irq_line( 0x01_00_0020 , true ) . is_ok( ) ) ;
1524
+
1525
+ // Case 2: using irq_type = 2, vcpu_index = 0, irq_id = 16 (decimal), the irq field in hex is: 0x02_00_0010
1526
+ assert ! ( vm_fd. set_irq_line( 0x02_00_0010 , true ) . is_ok( ) ) ;
1527
+ assert ! ( vm_fd. set_irq_line( 0x02_00_0010 , false ) . is_ok( ) ) ;
1528
+ assert ! ( vm_fd. set_irq_line( 0x02_00_0010 , true ) . is_ok( ) ) ;
1529
+ }
1530
+
1396
1531
#[ test]
1397
1532
#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
1398
1533
fn test_faulty_vm_fd ( ) {
0 commit comments