@@ -695,10 +695,9 @@ static enum pkvm_page_state guest_get_page_state(kvm_pte_t pte, u64 addr)
695695 return pkvm_getstate (kvm_pgtable_stage2_pte_prot (pte ));
696696}
697697
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 ,
699699 u64 size , enum pkvm_page_state state )
700700{
701- struct pkvm_hyp_vm * vm = pkvm_hyp_vcpu_to_hyp_vm (vcpu );
702701 struct check_walk_data d = {
703702 .desired = state ,
704703 .get_page_state = guest_get_page_state ,
@@ -907,48 +906,72 @@ int __pkvm_host_unshare_ffa(u64 pfn, u64 nr_pages)
907906 return ret ;
908907}
909908
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 ,
911920 enum kvm_pgtable_prot prot )
912921{
913922 struct pkvm_hyp_vm * vm = pkvm_hyp_vcpu_to_hyp_vm (vcpu );
914923 u64 phys = hyp_pfn_to_phys (pfn );
915924 u64 ipa = hyp_pfn_to_phys (gfn );
916- struct hyp_page * page ;
925+ u64 size ;
917926 int ret ;
918927
919928 if (prot & ~KVM_PGTABLE_PROT_RWX )
920929 return - EINVAL ;
921930
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 );
923936 if (ret )
924937 return ret ;
925938
926939 host_lock_component ();
927940 guest_lock_component (vm );
928941
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 );
930943 if (ret )
931944 goto unlock ;
932945
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+ }
946965 }
947966
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 ,
949973 pkvm_mkstate (prot , PKVM_PAGE_SHARED_BORROWED ),
950974 & vcpu -> vcpu .arch .pkvm_memcache , 0 ));
951- page -> host_share_guest_count ++ ;
952975
953976unlock :
954977 guest_unlock_component (vm );
@@ -1169,6 +1192,9 @@ static void assert_page_state(void)
11691192 struct pkvm_hyp_vcpu * vcpu = & selftest_vcpu ;
11701193 u64 phys = hyp_virt_to_phys (virt );
11711194 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 );
11721198
11731199 host_lock_component ();
11741200 WARN_ON (__host_check_page_state_range (phys , size , selftest_state .host ));
@@ -1179,8 +1205,8 @@ static void assert_page_state(void)
11791205 hyp_unlock_component ();
11801206
11811207 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 ]));
11841210 guest_unlock_component (& selftest_vm );
11851211}
11861212
@@ -1218,7 +1244,7 @@ void pkvm_ownership_selftest(void *base)
12181244 assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
12191245 assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
12201246 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 );
12221248 assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
12231249
12241250 selftest_state .host = PKVM_PAGE_OWNED ;
@@ -1237,7 +1263,7 @@ void pkvm_ownership_selftest(void *base)
12371263 assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
12381264 assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
12391265 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 );
12411267 assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
12421268
12431269 assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
@@ -1249,7 +1275,7 @@ void pkvm_ownership_selftest(void *base)
12491275 assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
12501276 assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
12511277 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 );
12531279 assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
12541280
12551281 hyp_unpin_shared_mem (virt , virt + size );
@@ -1268,7 +1294,7 @@ void pkvm_ownership_selftest(void *base)
12681294 assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
12691295 assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
12701296 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 );
12721298 assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
12731299 assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
12741300
@@ -1279,8 +1305,8 @@ void pkvm_ownership_selftest(void *base)
12791305
12801306 selftest_state .host = PKVM_PAGE_SHARED_OWNED ;
12811307 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 );
12841310 assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
12851311 assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
12861312 assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
@@ -1289,7 +1315,7 @@ void pkvm_ownership_selftest(void *base)
12891315 assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
12901316
12911317 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 );
12931319 WARN_ON (hyp_virt_to_page (virt )-> host_share_guest_count != 2 );
12941320
12951321 selftest_state .guest [0 ] = PKVM_NOPAGE ;
0 commit comments