@@ -980,10 +980,9 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, u64 nr_pages, struct pkvm_hyp_vcpu
980980 return ret ;
981981}
982982
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 )
984984{
985985 enum pkvm_page_state state ;
986- struct hyp_page * page ;
987986 kvm_pte_t pte ;
988987 u64 phys ;
989988 s8 level ;
@@ -994,51 +993,57 @@ static int __check_host_shared_guest(struct pkvm_hyp_vm *vm, u64 *__phys, u64 ip
994993 return ret ;
995994 if (!kvm_pte_valid (pte ))
996995 return - ENOENT ;
997- if (level != KVM_PGTABLE_LAST_LEVEL )
996+ if (kvm_granule_size ( level ) != size )
998997 return - E2BIG ;
999998
1000999 state = guest_get_page_state (pte , ipa );
10011000 if (state != PKVM_PAGE_SHARED_BORROWED )
10021001 return - EPERM ;
10031002
10041003 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 );
10061005 if (WARN_ON (ret ))
10071006 return ret ;
10081007
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+ }
10141014
10151015 * __phys = phys ;
10161016
10171017 return 0 ;
10181018}
10191019
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 )
10211021{
10221022 u64 ipa = hyp_pfn_to_phys (gfn );
1023- struct hyp_page * page ;
1024- u64 phys ;
1023+ u64 size , phys ;
10251024 int ret ;
10261025
1026+ ret = __guest_check_transition_size (0 , ipa , nr_pages , & size );
1027+ if (ret )
1028+ return ret ;
1029+
10271030 host_lock_component ();
10281031 guest_lock_component (vm );
10291032
1030- ret = __check_host_shared_guest (vm , & phys , ipa );
1033+ ret = __check_host_shared_guest (vm , & phys , ipa , size );
10311034 if (ret )
10321035 goto unlock ;
10331036
1034- ret = kvm_pgtable_stage2_unmap (& vm -> pgt , ipa , PAGE_SIZE );
1037+ ret = kvm_pgtable_stage2_unmap (& vm -> pgt , ipa , size );
10351038 if (ret )
10361039 goto unlock ;
10371040
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+ }
10421047
10431048unlock :
10441049 guest_unlock_component (vm );
@@ -1058,7 +1063,7 @@ static void assert_host_shared_guest(struct pkvm_hyp_vm *vm, u64 ipa)
10581063 host_lock_component ();
10591064 guest_lock_component (vm );
10601065
1061- ret = __check_host_shared_guest (vm , & phys , ipa );
1066+ ret = __check_host_shared_guest (vm , & phys , ipa , PAGE_SIZE );
10621067
10631068 guest_unlock_component (vm );
10641069 host_unlock_component ();
@@ -1245,15 +1250,15 @@ void pkvm_ownership_selftest(void *base)
12451250 assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
12461251 assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
12471252 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 );
12491254
12501255 selftest_state .host = PKVM_PAGE_OWNED ;
12511256 selftest_state .hyp = PKVM_NOPAGE ;
12521257 assert_transition_res (0 , __pkvm_hyp_donate_host , pfn , 1 );
12531258 assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
12541259 assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
12551260 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 );
12571262 assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
12581263
12591264 selftest_state .host = PKVM_PAGE_SHARED_OWNED ;
@@ -1264,7 +1269,7 @@ void pkvm_ownership_selftest(void *base)
12641269 assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
12651270 assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
12661271 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 );
12681273
12691274 assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
12701275 assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
@@ -1276,7 +1281,7 @@ void pkvm_ownership_selftest(void *base)
12761281 assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
12771282 assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
12781283 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 );
12801285
12811286 hyp_unpin_shared_mem (virt , virt + size );
12821287 assert_page_state ();
@@ -1295,7 +1300,7 @@ void pkvm_ownership_selftest(void *base)
12951300 assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
12961301 assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
12971302 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 );
12991304 assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
13001305
13011306 selftest_state .host = PKVM_PAGE_OWNED ;
@@ -1319,11 +1324,11 @@ void pkvm_ownership_selftest(void *base)
13191324 WARN_ON (hyp_virt_to_page (virt )-> host_share_guest_count != 2 );
13201325
13211326 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 );
13231328
13241329 selftest_state .guest [1 ] = PKVM_NOPAGE ;
13251330 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 );
13271332
13281333 selftest_state .host = PKVM_NOPAGE ;
13291334 selftest_state .hyp = PKVM_PAGE_OWNED ;
0 commit comments