@@ -18,12 +18,19 @@ impl std::ops::Deref for GICv3 {
1818    } 
1919} 
2020
21+ impl  std:: ops:: DerefMut  for  GICv3  { 
22+     fn  deref_mut ( & mut  self )  -> & mut  Self :: Target  { 
23+         & mut  self . 0 
24+     } 
25+ } 
26+ 
2127impl  GICv3  { 
2228    // Unfortunately bindgen omits defines that are based on other defines. 
2329    // See arch/arm64/include/uapi/asm/kvm.h file from the linux kernel. 
2430    const  SZ_64K :  u64  = 0x0001_0000 ; 
2531    const  KVM_VGIC_V3_DIST_SIZE :  u64  = GICv3 :: SZ_64K ; 
2632    const  KVM_VGIC_V3_REDIST_SIZE :  u64  = ( 2  *  GICv3 :: SZ_64K ) ; 
33+     const  GIC_V3_ITS_SIZE :  u64  = 0x2_0000 ; 
2734
2835    // Device trees specific constants 
2936    const  ARCH_GIC_V3_MAINT_IRQ :  u32  = 9 ; 
@@ -48,6 +55,16 @@ impl GICv3 {
4855        vcpu_count *  GICv3 :: KVM_VGIC_V3_REDIST_SIZE 
4956    } 
5057
58+     /// Get the MSI address 
59+      fn  get_msi_address ( vcpu_count :  u64 )  -> u64  { 
60+         Self :: get_redists_addr ( vcpu_count)  - GICv3 :: GIC_V3_ITS_SIZE 
61+     } 
62+ 
63+     /// Get the MSI size 
64+      const  fn  get_msi_size ( )  -> u64  { 
65+         GICv3 :: GIC_V3_ITS_SIZE 
66+     } 
67+ 
5168    pub  const  VERSION :  u32  = kvm_bindings:: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_V3; 
5269
5370    pub  fn  fdt_compatibility ( & self )  -> & str  { 
@@ -59,30 +76,43 @@ impl GICv3 {
5976    } 
6077
6178    /// Create the GIC device object 
62-      pub  fn  create_device ( fd :  DeviceFd ,  vcpu_count :  u64 )  -> Self  { 
63-         GICv3 ( super :: GIC  { 
64-             fd, 
79+      pub  fn  create_device ( vm :  & VmFd ,  vcpu_count :  u64 )  -> Result < Self ,  GicError >  { 
80+         // Create the GIC device 
81+         let  mut  gic_device = kvm_bindings:: kvm_create_device  { 
82+             type_ :  Self :: VERSION , 
83+             fd :  0 , 
84+             flags :  0 , 
85+         } ; 
86+ 
87+         let  gic_fd = vm
88+             . create_device ( & mut  gic_device) 
89+             . map_err ( GicError :: CreateGIC ) ?; 
90+ 
91+         Ok ( GICv3 ( super :: GIC  { 
92+             fd :  gic_fd, 
6593            properties :  [ 
6694                GICv3 :: get_dist_addr ( ) , 
6795                GICv3 :: get_dist_size ( ) , 
6896                GICv3 :: get_redists_addr ( vcpu_count) , 
6997                GICv3 :: get_redists_size ( vcpu_count) , 
7098            ] , 
99+             msi_properties :  Some ( [ GICv3 :: get_msi_address ( vcpu_count) ,  GICv3 :: get_msi_size ( ) ] ) , 
71100            vcpu_count, 
72-         } ) 
101+             its_device :  None , 
102+         } ) ) 
73103    } 
74104
75105    pub  fn  save_device ( & self ,  mpidrs :  & [ u64 ] )  -> Result < GicState ,  GicError >  { 
76-         regs:: save_state ( & self . fd ,  mpidrs) 
106+         regs:: save_state ( & self . fd ,  self . its_device . as_ref ( ) . unwrap ( ) ,   mpidrs) 
77107    } 
78108
79109    pub  fn  restore_device ( & self ,  mpidrs :  & [ u64 ] ,  state :  & GicState )  -> Result < ( ) ,  GicError >  { 
80-         regs:: restore_state ( & self . fd ,  mpidrs,  state) 
110+         regs:: restore_state ( & self . fd ,  self . its_device . as_ref ( ) . unwrap ( ) ,   mpidrs,  state) 
81111    } 
82112
83113    pub  fn  init_device_attributes ( gic_device :  & Self )  -> Result < ( ) ,  GicError >  { 
84114        // Setting up the distributor attribute. 
85-         // We are placing the GIC below 1GB so we need to substract  the size of the distributor. 
115+         // We are placing the GIC below 1GB so we need to subtract  the size of the distributor. 
86116        Self :: set_device_attribute ( 
87117            gic_device. device_fd ( ) , 
88118            kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_ADDR , 
@@ -104,25 +134,45 @@ impl GICv3 {
104134        Ok ( ( ) ) 
105135    } 
106136
107-     /// Initialize a GIC device 
108-      pub   fn   init_device ( vm :   & VmFd )  ->  Result < DeviceFd ,   GicError >   { 
109-         let  mut  gic_device  = kvm_bindings:: kvm_create_device  { 
110-             type_ :  Self :: VERSION , 
137+     fn   init_its ( vm :   & VmFd ,   gic_device :   & mut   Self )  ->  Result < ( ) ,   GicError >   { 
138+          // ITS part attributes 
139+         let  mut  its_device  = kvm_bindings:: kvm_create_device  { 
140+             type_ :  kvm_bindings :: kvm_device_type_KVM_DEV_TYPE_ARM_VGIC_ITS , 
111141            fd :  0 , 
112142            flags :  0 , 
113143        } ; 
114144
115-         vm. create_device ( & mut  gic_device) 
116-             . map_err ( GicError :: CreateGIC ) 
145+         let  its_fd = vm
146+             . create_device ( & mut  its_device) 
147+             . map_err ( GicError :: CreateGIC ) ?; 
148+ 
149+         // Setting up the ITS attributes 
150+         Self :: set_device_attribute ( 
151+             & its_fd, 
152+             kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_ADDR , 
153+             u64:: from ( kvm_bindings:: KVM_VGIC_ITS_ADDR_TYPE ) , 
154+             & Self :: get_msi_address ( gic_device. vcpu_count ( ) )  as  * const  u64  as  u64 , 
155+             0 , 
156+         ) ?; 
157+ 
158+         Self :: set_device_attribute ( 
159+             & its_fd, 
160+             kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL , 
161+             u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_CTRL_INIT ) , 
162+             0 , 
163+             0 , 
164+         ) ?; 
165+ 
166+         gic_device. its_device  = Some ( its_fd) ; 
167+         Ok ( ( ) ) 
117168    } 
118169
119170    /// Method to initialize the GIC device 
120171     pub  fn  create ( vm :  & VmFd ,  vcpu_count :  u64 )  -> Result < Self ,  GicError >  { 
121-         let  vgic_fd = Self :: init_device ( vm) ?; 
122- 
123-         let  device = Self :: create_device ( vgic_fd,  vcpu_count) ; 
172+         let  mut  device = Self :: create_device ( vm,  vcpu_count) ?; 
124173
125174        Self :: init_device_attributes ( & device) ?; 
175+         Self :: init_its ( vm,  & mut  device) ?; 
126176
127177        Self :: finalize_device ( & device) ?; 
128178
@@ -184,16 +234,27 @@ impl GICv3 {
184234/// RDIST pending tables into guest RAM. 
185235/// 
186236/// The tables get flushed to guest RAM whenever the VM gets stopped. 
187- fn  save_pending_tables ( fd :  & DeviceFd )  -> Result < ( ) ,  GicError >  { 
237+ fn  save_pending_tables ( gic_device :   & DeviceFd ,   its_device :  & DeviceFd )  -> Result < ( ) ,  GicError >  { 
188238    let  init_gic_attr = kvm_bindings:: kvm_device_attr  { 
189239        group :  kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL , 
190240        attr :  u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES ) , 
191241        addr :  0 , 
192242        flags :  0 , 
193243    } ; 
194-     fd . set_device_attr ( & init_gic_attr) . map_err ( |err| { 
244+     gic_device . set_device_attr ( & init_gic_attr) . map_err ( |err| { 
195245        GicError :: DeviceAttribute ( err,  true ,  kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ) 
196-     } ) 
246+     } ) ?; 
247+     let  save_its_tables_attr = kvm_bindings:: kvm_device_attr  { 
248+         group :  kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL , 
249+         attr :  u64:: from ( kvm_bindings:: KVM_DEV_ARM_ITS_SAVE_TABLES ) , 
250+         addr :  0 , 
251+         flags :  0 , 
252+     } ; 
253+     its_device
254+         . set_device_attr ( & save_its_tables_attr) 
255+         . map_err ( |err| { 
256+             GicError :: DeviceAttribute ( err,  true ,  kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ) 
257+         } ) 
197258} 
198259
199260#[ cfg( test) ]  
@@ -211,11 +272,11 @@ mod tests {
211272        let  kvm = Kvm :: new ( ) . unwrap ( ) ; 
212273        let  vm = kvm. create_vm ( ) . unwrap ( ) ; 
213274        let  gic = create_gic ( & vm,  1 ,  Some ( GICVersion :: GICV3 ) ) . expect ( "Cannot create gic" ) ; 
214-         save_pending_tables ( gic. device_fd ( ) ) . unwrap ( ) ; 
275+         save_pending_tables ( gic. device_fd ( ) ,  gic . its_fd ( ) . unwrap ( ) ) . unwrap ( ) ; 
215276
216277        unsafe  {  libc:: close ( gic. device_fd ( ) . as_raw_fd ( ) )  } ; 
217278
218-         let  res = save_pending_tables ( gic. device_fd ( ) ) ; 
279+         let  res = save_pending_tables ( gic. device_fd ( ) ,  gic . its_fd ( ) . unwrap ( ) ) ; 
219280        assert_eq ! ( 
220281            format!( "{:?}" ,  res. unwrap_err( ) ) , 
221282            "DeviceAttribute(Error(9), true, 4)" 
0 commit comments