@@ -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
@@ -180,20 +230,41 @@ impl GICv3 {
180230 }
181231}
182232
233+ /// Function that saves/restores ITS tables into guest RAM.
234+ pub fn gicv3_its_tables_access ( its_device : & DeviceFd , save : bool ) -> Result < ( ) , GicError > {
235+ let attr = if save {
236+ u64:: from ( kvm_bindings:: KVM_DEV_ARM_ITS_SAVE_TABLES )
237+ } else {
238+ u64:: from ( kvm_bindings:: KVM_DEV_ARM_ITS_RESTORE_TABLES )
239+ } ;
240+
241+ let init_gic_attr = kvm_bindings:: kvm_device_attr {
242+ group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
243+ attr,
244+ addr : 0 ,
245+ flags : 0 ,
246+ } ;
247+
248+ its_device. set_device_attr ( & init_gic_attr) . map_err ( |err| {
249+ GicError :: DeviceAttribute ( err, true , kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL )
250+ } )
251+ }
252+
183253/// Function that flushes
184254/// RDIST pending tables into guest RAM.
185255///
186256/// The tables get flushed to guest RAM whenever the VM gets stopped.
187- fn save_pending_tables ( fd : & DeviceFd ) -> Result < ( ) , GicError > {
257+ fn save_pending_tables ( gic_device : & DeviceFd , its_device : & DeviceFd ) -> Result < ( ) , GicError > {
188258 let init_gic_attr = kvm_bindings:: kvm_device_attr {
189259 group : kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL ,
190260 attr : u64:: from ( kvm_bindings:: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES ) ,
191261 addr : 0 ,
192262 flags : 0 ,
193263 } ;
194- fd . set_device_attr ( & init_gic_attr) . map_err ( |err| {
264+ gic_device . set_device_attr ( & init_gic_attr) . map_err ( |err| {
195265 GicError :: DeviceAttribute ( err, true , kvm_bindings:: KVM_DEV_ARM_VGIC_GRP_CTRL )
196- } )
266+ } ) ?;
267+ gicv3_its_tables_access ( its_device, true )
197268}
198269
199270#[ cfg( test) ]
@@ -211,11 +282,11 @@ mod tests {
211282 let kvm = Kvm :: new ( ) . unwrap ( ) ;
212283 let vm = kvm. create_vm ( ) . unwrap ( ) ;
213284 let gic = create_gic ( & vm, 1 , Some ( GICVersion :: GICV3 ) ) . expect ( "Cannot create gic" ) ;
214- save_pending_tables ( gic. device_fd ( ) ) . unwrap ( ) ;
285+ save_pending_tables ( gic. device_fd ( ) , gic . its_fd ( ) . unwrap ( ) ) . unwrap ( ) ;
215286
216287 unsafe { libc:: close ( gic. device_fd ( ) . as_raw_fd ( ) ) } ;
217288
218- let res = save_pending_tables ( gic. device_fd ( ) ) ;
289+ let res = save_pending_tables ( gic. device_fd ( ) , gic . its_fd ( ) . unwrap ( ) ) ;
219290 assert_eq ! (
220291 format!( "{:?}" , res. unwrap_err( ) ) ,
221292 "DeviceAttribute(Error(9), true, 4)"
0 commit comments