@@ -1466,6 +1466,16 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
14661466{
14671467 mutex_lock (& its -> cmd_lock );
14681468
1469+ /*
1470+ * It is UNPREDICTABLE to enable the ITS if any of the CBASER or
1471+ * device/collection BASER are invalid
1472+ */
1473+ if (!its -> enabled && (val & GITS_CTLR_ENABLE ) &&
1474+ (!(its -> baser_device_table & GITS_BASER_VALID ) ||
1475+ !(its -> baser_coll_table & GITS_BASER_VALID ) ||
1476+ !(its -> cbaser & GITS_CBASER_VALID )))
1477+ goto out ;
1478+
14691479 its -> enabled = !!(val & GITS_CTLR_ENABLE );
14701480
14711481 /*
@@ -1474,6 +1484,7 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
14741484 */
14751485 vgic_its_process_commands (kvm , its );
14761486
1487+ out :
14771488 mutex_unlock (& its -> cmd_lock );
14781489}
14791490
@@ -1801,37 +1812,33 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
18011812static int scan_its_table (struct vgic_its * its , gpa_t base , int size , int esz ,
18021813 int start_id , entry_fn_t fn , void * opaque )
18031814{
1804- void * entry = kzalloc (esz , GFP_KERNEL );
18051815 struct kvm * kvm = its -> dev -> kvm ;
18061816 unsigned long len = size ;
18071817 int id = start_id ;
18081818 gpa_t gpa = base ;
1819+ char entry [esz ];
18091820 int ret ;
18101821
1822+ memset (entry , 0 , esz );
1823+
18111824 while (len > 0 ) {
18121825 int next_offset ;
18131826 size_t byte_offset ;
18141827
18151828 ret = kvm_read_guest (kvm , gpa , entry , esz );
18161829 if (ret )
1817- goto out ;
1830+ return ret ;
18181831
18191832 next_offset = fn (its , id , entry , opaque );
1820- if (next_offset <= 0 ) {
1821- ret = next_offset ;
1822- goto out ;
1823- }
1833+ if (next_offset <= 0 )
1834+ return next_offset ;
18241835
18251836 byte_offset = next_offset * esz ;
18261837 id += next_offset ;
18271838 gpa += byte_offset ;
18281839 len -= byte_offset ;
18291840 }
1830- ret = 1 ;
1831-
1832- out :
1833- kfree (entry );
1834- return ret ;
1841+ return 1 ;
18351842}
18361843
18371844/**
@@ -1940,6 +1947,14 @@ static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
19401947 return 0 ;
19411948}
19421949
1950+ /**
1951+ * vgic_its_restore_itt - restore the ITT of a device
1952+ *
1953+ * @its: its handle
1954+ * @dev: device handle
1955+ *
1956+ * Return 0 on success, < 0 on error
1957+ */
19431958static int vgic_its_restore_itt (struct vgic_its * its , struct its_device * dev )
19441959{
19451960 const struct vgic_its_abi * abi = vgic_its_get_abi (its );
@@ -1951,6 +1966,10 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
19511966 ret = scan_its_table (its , base , max_size , ite_esz , 0 ,
19521967 vgic_its_restore_ite , dev );
19531968
1969+ /* scan_its_table returns +1 if all ITEs are invalid */
1970+ if (ret > 0 )
1971+ ret = 0 ;
1972+
19541973 return ret ;
19551974}
19561975
@@ -2048,11 +2067,12 @@ static int vgic_its_device_cmp(void *priv, struct list_head *a,
20482067static int vgic_its_save_device_tables (struct vgic_its * its )
20492068{
20502069 const struct vgic_its_abi * abi = vgic_its_get_abi (its );
2070+ u64 baser = its -> baser_device_table ;
20512071 struct its_device * dev ;
20522072 int dte_esz = abi -> dte_esz ;
2053- u64 baser ;
20542073
2055- baser = its -> baser_device_table ;
2074+ if (!(baser & GITS_BASER_VALID ))
2075+ return 0 ;
20562076
20572077 list_sort (NULL , & its -> device_list , vgic_its_device_cmp );
20582078
@@ -2107,10 +2127,7 @@ static int handle_l1_dte(struct vgic_its *its, u32 id, void *addr,
21072127 ret = scan_its_table (its , gpa , SZ_64K , dte_esz ,
21082128 l2_start_id , vgic_its_restore_dte , NULL );
21092129
2110- if (ret <= 0 )
2111- return ret ;
2112-
2113- return 1 ;
2130+ return ret ;
21142131}
21152132
21162133/**
@@ -2140,8 +2157,9 @@ static int vgic_its_restore_device_tables(struct vgic_its *its)
21402157 vgic_its_restore_dte , NULL );
21412158 }
21422159
2160+ /* scan_its_table returns +1 if all entries are invalid */
21432161 if (ret > 0 )
2144- ret = - EINVAL ;
2162+ ret = 0 ;
21452163
21462164 return ret ;
21472165}
@@ -2198,17 +2216,17 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
21982216static int vgic_its_save_collection_table (struct vgic_its * its )
21992217{
22002218 const struct vgic_its_abi * abi = vgic_its_get_abi (its );
2219+ u64 baser = its -> baser_coll_table ;
2220+ gpa_t gpa = BASER_ADDRESS (baser );
22012221 struct its_collection * collection ;
22022222 u64 val ;
2203- gpa_t gpa ;
22042223 size_t max_size , filled = 0 ;
22052224 int ret , cte_esz = abi -> cte_esz ;
22062225
2207- gpa = BASER_ADDRESS (its -> baser_coll_table );
2208- if (!gpa )
2226+ if (!(baser & GITS_BASER_VALID ))
22092227 return 0 ;
22102228
2211- max_size = GITS_BASER_NR_PAGES (its -> baser_coll_table ) * SZ_64K ;
2229+ max_size = GITS_BASER_NR_PAGES (baser ) * SZ_64K ;
22122230
22132231 list_for_each_entry (collection , & its -> collection_list , coll_list ) {
22142232 ret = vgic_its_save_cte (its , collection , gpa , cte_esz );
@@ -2239,17 +2257,18 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
22392257static int vgic_its_restore_collection_table (struct vgic_its * its )
22402258{
22412259 const struct vgic_its_abi * abi = vgic_its_get_abi (its );
2260+ u64 baser = its -> baser_coll_table ;
22422261 int cte_esz = abi -> cte_esz ;
22432262 size_t max_size , read = 0 ;
22442263 gpa_t gpa ;
22452264 int ret ;
22462265
2247- if (!(its -> baser_coll_table & GITS_BASER_VALID ))
2266+ if (!(baser & GITS_BASER_VALID ))
22482267 return 0 ;
22492268
2250- gpa = BASER_ADDRESS (its -> baser_coll_table );
2269+ gpa = BASER_ADDRESS (baser );
22512270
2252- max_size = GITS_BASER_NR_PAGES (its -> baser_coll_table ) * SZ_64K ;
2271+ max_size = GITS_BASER_NR_PAGES (baser ) * SZ_64K ;
22532272
22542273 while (read < max_size ) {
22552274 ret = vgic_its_restore_cte (its , gpa , cte_esz );
@@ -2258,6 +2277,10 @@ static int vgic_its_restore_collection_table(struct vgic_its *its)
22582277 gpa += cte_esz ;
22592278 read += cte_esz ;
22602279 }
2280+
2281+ if (ret > 0 )
2282+ return 0 ;
2283+
22612284 return ret ;
22622285}
22632286
0 commit comments