@@ -980,10 +980,9 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu
980
980
return ret ;
981
981
}
982
982
983
- static int __check_host_shared_guest (struct pkvm_hyp_vm * vm , u64 * __phys , u64 ipa )
983
+ static int __check_host_shared_guest (struct pkvm_hyp_vm * vm , u64 * __phys , u64 ipa , u64 size )
984
984
{
985
985
enum pkvm_page_state state ;
986
- struct hyp_page * page ;
987
986
kvm_pte_t pte ;
988
987
u64 phys ;
989
988
s8 level ;
@@ -994,51 +993,57 @@ static int __check_host_shared_guest(struct pkvm_hyp_vm *vm, u64 *__phys, u64 ip
994
993
return ret ;
995
994
if (!kvm_pte_valid (pte ))
996
995
return - ENOENT ;
997
- if (level != KVM_PGTABLE_LAST_LEVEL )
996
+ if (kvm_granule_size ( level ) != size )
998
997
return - E2BIG ;
999
998
1000
999
state = guest_get_page_state (pte , ipa );
1001
1000
if (state != PKVM_PAGE_SHARED_BORROWED )
1002
1001
return - EPERM ;
1003
1002
1004
1003
phys = kvm_pte_to_phys (pte );
1005
- ret = check_range_allowed_memory (phys , phys + PAGE_SIZE );
1004
+ ret = check_range_allowed_memory (phys , phys + size );
1006
1005
if (WARN_ON (ret ))
1007
1006
return ret ;
1008
1007
1009
- page = hyp_phys_to_page (phys );
1010
- if (get_host_state (page ) != PKVM_PAGE_SHARED_OWNED )
1011
- return - EPERM ;
1012
- if (WARN_ON (!page -> host_share_guest_count ))
1013
- return - EINVAL ;
1008
+ for_each_hyp_page (page , phys , size ) {
1009
+ if (get_host_state (page ) != PKVM_PAGE_SHARED_OWNED )
1010
+ return - EPERM ;
1011
+ if (WARN_ON (!page -> host_share_guest_count ))
1012
+ return - EINVAL ;
1013
+ }
1014
1014
1015
1015
* __phys = phys ;
1016
1016
1017
1017
return 0 ;
1018
1018
}
1019
1019
1020
- int __pkvm_host_unshare_guest (u64 gfn , struct pkvm_hyp_vm * vm )
1020
+ int __pkvm_host_unshare_guest (u64 gfn , u64 nr_pages , struct pkvm_hyp_vm * vm )
1021
1021
{
1022
1022
u64 ipa = hyp_pfn_to_phys (gfn );
1023
- struct hyp_page * page ;
1024
- u64 phys ;
1023
+ u64 size , phys ;
1025
1024
int ret ;
1026
1025
1026
+ ret = __guest_check_transition_size (0 , ipa , nr_pages , & size );
1027
+ if (ret )
1028
+ return ret ;
1029
+
1027
1030
host_lock_component ();
1028
1031
guest_lock_component (vm );
1029
1032
1030
- ret = __check_host_shared_guest (vm , & phys , ipa );
1033
+ ret = __check_host_shared_guest (vm , & phys , ipa , size );
1031
1034
if (ret )
1032
1035
goto unlock ;
1033
1036
1034
- ret = kvm_pgtable_stage2_unmap (& vm -> pgt , ipa , PAGE_SIZE );
1037
+ ret = kvm_pgtable_stage2_unmap (& vm -> pgt , ipa , size );
1035
1038
if (ret )
1036
1039
goto unlock ;
1037
1040
1038
- page = hyp_phys_to_page (phys );
1039
- page -> host_share_guest_count -- ;
1040
- if (!page -> host_share_guest_count )
1041
- WARN_ON (__host_set_page_state_range (phys , PAGE_SIZE , PKVM_PAGE_OWNED ));
1041
+ for_each_hyp_page (page , phys , size ) {
1042
+ /* __check_host_shared_guest() protects against underflow */
1043
+ page -> host_share_guest_count -- ;
1044
+ if (!page -> host_share_guest_count )
1045
+ set_host_state (page , PKVM_PAGE_OWNED );
1046
+ }
1042
1047
1043
1048
unlock :
1044
1049
guest_unlock_component (vm );
@@ -1058,7 +1063,7 @@ static void assert_host_shared_guest(struct pkvm_hyp_vm *vm, u64 ipa)
1058
1063
host_lock_component ();
1059
1064
guest_lock_component (vm );
1060
1065
1061
- ret = __check_host_shared_guest (vm , & phys , ipa );
1066
+ ret = __check_host_shared_guest (vm , & phys , ipa , PAGE_SIZE );
1062
1067
1063
1068
guest_unlock_component (vm );
1064
1069
host_unlock_component ();
@@ -1245,15 +1250,15 @@ void pkvm_ownership_selftest(void *base)
1245
1250
assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
1246
1251
assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1247
1252
assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1248
- assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1253
+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , 1 , vm );
1249
1254
1250
1255
selftest_state .host = PKVM_PAGE_OWNED ;
1251
1256
selftest_state .hyp = PKVM_NOPAGE ;
1252
1257
assert_transition_res (0 , __pkvm_hyp_donate_host , pfn , 1 );
1253
1258
assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1254
1259
assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
1255
1260
assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
1256
- assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1261
+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , 1 , vm );
1257
1262
assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1258
1263
1259
1264
selftest_state .host = PKVM_PAGE_SHARED_OWNED ;
@@ -1264,7 +1269,7 @@ void pkvm_ownership_selftest(void *base)
1264
1269
assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1265
1270
assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1266
1271
assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1267
- assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1272
+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , 1 , vm );
1268
1273
1269
1274
assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
1270
1275
assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
@@ -1276,7 +1281,7 @@ void pkvm_ownership_selftest(void *base)
1276
1281
assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1277
1282
assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1278
1283
assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1279
- assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1284
+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , 1 , vm );
1280
1285
1281
1286
hyp_unpin_shared_mem (virt , virt + size );
1282
1287
assert_page_state ();
@@ -1295,7 +1300,7 @@ void pkvm_ownership_selftest(void *base)
1295
1300
assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
1296
1301
assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1297
1302
assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , 1 , vcpu , prot );
1298
- assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1303
+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , 1 , vm );
1299
1304
assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1300
1305
1301
1306
selftest_state .host = PKVM_PAGE_OWNED ;
@@ -1319,11 +1324,11 @@ void pkvm_ownership_selftest(void *base)
1319
1324
WARN_ON (hyp_virt_to_page (virt )-> host_share_guest_count != 2 );
1320
1325
1321
1326
selftest_state .guest [0 ] = PKVM_NOPAGE ;
1322
- assert_transition_res (0 , __pkvm_host_unshare_guest , gfn , vm );
1327
+ assert_transition_res (0 , __pkvm_host_unshare_guest , gfn , 1 , vm );
1323
1328
1324
1329
selftest_state .guest [1 ] = PKVM_NOPAGE ;
1325
1330
selftest_state .host = PKVM_PAGE_OWNED ;
1326
- assert_transition_res (0 , __pkvm_host_unshare_guest , gfn + 1 , vm );
1331
+ assert_transition_res (0 , __pkvm_host_unshare_guest , gfn + 1 , 1 , vm );
1327
1332
1328
1333
selftest_state .host = PKVM_NOPAGE ;
1329
1334
selftest_state .hyp = PKVM_PAGE_OWNED ;
0 commit comments