@@ -695,10 +695,9 @@ static enum pkvm_page_state guest_get_page_state(kvm_pte_t pte, u64 addr)
695
695
return pkvm_getstate (kvm_pgtable_stage2_pte_prot (pte ));
696
696
}
697
697
698
- static int __guest_check_page_state_range (struct pkvm_hyp_vcpu * vcpu , u64 addr ,
698
+ static int __guest_check_page_state_range (struct pkvm_hyp_vm * vm , u64 addr ,
699
699
u64 size , enum pkvm_page_state state )
700
700
{
701
- struct pkvm_hyp_vm * vm = pkvm_hyp_vcpu_to_hyp_vm (vcpu );
702
701
struct check_walk_data d = {
703
702
.desired = state ,
704
703
.get_page_state = guest_get_page_state ,
@@ -907,48 +906,72 @@ int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages)
907
906
return ret ;
908
907
}
909
908
910
- int __pkvm_host_share_guest (u64 pfn , u64 gfn , struct pkvm_hyp_vcpu * vcpu ,
909
+ static int __guest_check_transition_size (u64 phys , u64 ipa , u64 nr_pages , u64 * size )
910
+ {
911
+ if (nr_pages == 1 ) {
912
+ * size = PAGE_SIZE ;
913
+ return 0 ;
914
+ }
915
+
916
+ return - EINVAL ;
917
+ }
918
+
919
+ int __pkvm_host_share_guest (u64 pfn , u64 gfn , u64 nr_pages , struct pkvm_hyp_vcpu * vcpu ,
911
920
enum kvm_pgtable_prot prot )
912
921
{
913
922
struct pkvm_hyp_vm * vm = pkvm_hyp_vcpu_to_hyp_vm (vcpu );
914
923
u64 phys = hyp_pfn_to_phys (pfn );
915
924
u64 ipa = hyp_pfn_to_phys (gfn );
916
- struct hyp_page * page ;
925
+ u64 size ;
917
926
int ret ;
918
927
919
928
if (prot & ~KVM_PGTABLE_PROT_RWX )
920
929
return - EINVAL ;
921
930
922
- ret = check_range_allowed_memory (phys , phys + PAGE_SIZE );
931
+ ret = __guest_check_transition_size (phys , ipa , nr_pages , & size );
932
+ if (ret )
933
+ return ret ;
934
+
935
+ ret = check_range_allowed_memory (phys , phys + size );
923
936
if (ret )
924
937
return ret ;
925
938
926
939
host_lock_component ();
927
940
guest_lock_component (vm );
928
941
929
- ret = __guest_check_page_state_range (vcpu , ipa , PAGE_SIZE , PKVM_NOPAGE );
942
+ ret = __guest_check_page_state_range (vm , ipa , size , PKVM_NOPAGE );
930
943
if (ret )
931
944
goto unlock ;
932
945
933
- page = hyp_phys_to_page (phys );
934
- switch (get_host_state (page )) {
935
- case PKVM_PAGE_OWNED :
936
- WARN_ON (__host_set_page_state_range (phys , PAGE_SIZE , PKVM_PAGE_SHARED_OWNED ));
937
- break ;
938
- case PKVM_PAGE_SHARED_OWNED :
939
- if (page -> host_share_guest_count )
940
- break ;
941
- /* Only host to np-guest multi-sharing is tolerated */
942
- fallthrough ;
943
- default :
944
- ret = - EPERM ;
945
- goto unlock ;
946
+ for_each_hyp_page (page , phys , size ) {
947
+ switch (get_host_state (page )) {
948
+ case PKVM_PAGE_OWNED :
949
+ continue ;
950
+ case PKVM_PAGE_SHARED_OWNED :
951
+ if (page -> host_share_guest_count == U32_MAX ) {
952
+ ret = - EBUSY ;
953
+ goto unlock ;
954
+ }
955
+
956
+ /* Only host to np-guest multi-sharing is tolerated */
957
+ if (page -> host_share_guest_count )
958
+ continue ;
959
+
960
+ fallthrough ;
961
+ default :
962
+ ret = - EPERM ;
963
+ goto unlock ;
964
+ }
946
965
}
947
966
948
- WARN_ON (kvm_pgtable_stage2_map (& vm -> pgt , ipa , PAGE_SIZE , phys ,
967
+ for_each_hyp_page (page , phys , size ) {
968
+ set_host_state (page , PKVM_PAGE_SHARED_OWNED );
969
+ page -> host_share_guest_count ++ ;
970
+ }
971
+
972
+ WARN_ON (kvm_pgtable_stage2_map (& vm -> pgt , ipa , size , phys ,
949
973
pkvm_mkstate (prot , PKVM_PAGE_SHARED_BORROWED ),
950
974
& vcpu -> vcpu .arch .pkvm_memcache , 0 ));
951
- page -> host_share_guest_count ++ ;
952
975
953
976
unlock :
954
977
guest_unlock_component (vm );
@@ -1169,6 +1192,9 @@ static void assert_page_state(void)
1169
1192
struct pkvm_hyp_vcpu * vcpu = & selftest_vcpu ;
1170
1193
u64 phys = hyp_virt_to_phys (virt );
1171
1194
u64 ipa [2 ] = { selftest_ipa (), selftest_ipa () + PAGE_SIZE };
1195
+ struct pkvm_hyp_vm * vm ;
1196
+
1197
+ vm = pkvm_hyp_vcpu_to_hyp_vm (vcpu );
1172
1198
1173
1199
host_lock_component ();
1174
1200
WARN_ON (__host_check_page_state_range (phys , size , selftest_state .host ));
@@ -1179,8 +1205,8 @@ static void assert_page_state(void)
1179
1205
hyp_unlock_component ();
1180
1206
1181
1207
guest_lock_component (& selftest_vm );
1182
- WARN_ON (__guest_check_page_state_range (vcpu , ipa [0 ], size , selftest_state .guest [0 ]));
1183
- WARN_ON (__guest_check_page_state_range (vcpu , ipa [1 ], size , selftest_state .guest [1 ]));
1208
+ WARN_ON (__guest_check_page_state_range (vm , ipa [0 ], size , selftest_state .guest [0 ]));
1209
+ WARN_ON (__guest_check_page_state_range (vm , ipa [1 ], size , selftest_state .guest [1 ]));
1184
1210
guest_unlock_component (& selftest_vm );
1185
1211
}
1186
1212
@@ -1218,7 +1244,7 @@ void pkvm_ownership_selftest(void *base)
1218
1244
assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1219
1245
assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
1220
1246
assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1221
- assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1247
+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1222
1248
assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1223
1249
1224
1250
selftest_state .host = PKVM_PAGE_OWNED ;
@@ -1237,7 +1263,7 @@ void pkvm_ownership_selftest(void *base)
1237
1263
assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1238
1264
assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1239
1265
assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1240
- assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1266
+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1241
1267
assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1242
1268
1243
1269
assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
@@ -1249,7 +1275,7 @@ void pkvm_ownership_selftest(void *base)
1249
1275
assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1250
1276
assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1251
1277
assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1252
- assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1278
+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1253
1279
assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1254
1280
1255
1281
hyp_unpin_shared_mem (virt , virt + size );
@@ -1268,7 +1294,7 @@ void pkvm_ownership_selftest(void *base)
1268
1294
assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
1269
1295
assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
1270
1296
assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1271
- assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1297
+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1272
1298
assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1273
1299
assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1274
1300
@@ -1279,8 +1305,8 @@ void pkvm_ownership_selftest(void *base)
1279
1305
1280
1306
selftest_state .host = PKVM_PAGE_SHARED_OWNED ;
1281
1307
selftest_state .guest [0 ] = PKVM_PAGE_SHARED_BORROWED ;
1282
- assert_transition_res (0 , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1283
- assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1308
+ assert_transition_res (0 , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1309
+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1284
1310
assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1285
1311
assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1286
1312
assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
@@ -1289,7 +1315,7 @@ void pkvm_ownership_selftest(void *base)
1289
1315
assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1290
1316
1291
1317
selftest_state .guest [1 ] = PKVM_PAGE_SHARED_BORROWED ;
1292
- assert_transition_res (0 , __pkvm_host_share_guest , pfn , gfn + 1 , vcpu , prot );
1318
+ assert_transition_res (0 , __pkvm_host_share_guest , pfn , gfn + 1 , 1 , vcpu , prot );
1293
1319
WARN_ON (hyp_virt_to_page (virt )-> host_share_guest_count != 2 );
1294
1320
1295
1321
selftest_state .guest [0 ] = PKVM_NOPAGE ;
0 commit comments