@@ -921,7 +921,6 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu,
921921 if (page -> host_share_guest_count )
922922 break ;
923923 /* Only host to np-guest multi-sharing is tolerated */
924- WARN_ON (1 );
925924 fallthrough ;
926925 default :
927926 ret = - EPERM ;
@@ -1093,3 +1092,200 @@ int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu)
10931092
10941093 return 0 ;
10951094}
1095+
1096+ #ifdef CONFIG_NVHE_EL2_DEBUG
1097+ struct pkvm_expected_state {
1098+ enum pkvm_page_state host ;
1099+ enum pkvm_page_state hyp ;
1100+ enum pkvm_page_state guest [2 ]; /* [ gfn, gfn + 1 ] */
1101+ };
1102+
1103+ static struct pkvm_expected_state selftest_state ;
1104+ static struct hyp_page * selftest_page ;
1105+
1106+ static struct pkvm_hyp_vm selftest_vm = {
1107+ .kvm = {
1108+ .arch = {
1109+ .mmu = {
1110+ .arch = & selftest_vm .kvm .arch ,
1111+ .pgt = & selftest_vm .pgt ,
1112+ },
1113+ },
1114+ },
1115+ };
1116+
1117+ static struct pkvm_hyp_vcpu selftest_vcpu = {
1118+ .vcpu = {
1119+ .arch = {
1120+ .hw_mmu = & selftest_vm .kvm .arch .mmu ,
1121+ },
1122+ .kvm = & selftest_vm .kvm ,
1123+ },
1124+ };
1125+
1126+ static void init_selftest_vm (void * virt )
1127+ {
1128+ struct hyp_page * p = hyp_virt_to_page (virt );
1129+ int i ;
1130+
1131+ selftest_vm .kvm .arch .mmu .vtcr = host_mmu .arch .mmu .vtcr ;
1132+ WARN_ON (kvm_guest_prepare_stage2 (& selftest_vm , virt ));
1133+
1134+ for (i = 0 ; i < pkvm_selftest_pages (); i ++ ) {
1135+ if (p [i ].refcount )
1136+ continue ;
1137+ p [i ].refcount = 1 ;
1138+ hyp_put_page (& selftest_vm .pool , hyp_page_to_virt (& p [i ]));
1139+ }
1140+ }
1141+
1142+ static u64 selftest_ipa (void )
1143+ {
1144+ return BIT (selftest_vm .pgt .ia_bits - 1 );
1145+ }
1146+
1147+ static void assert_page_state (void )
1148+ {
1149+ void * virt = hyp_page_to_virt (selftest_page );
1150+ u64 size = PAGE_SIZE << selftest_page -> order ;
1151+ struct pkvm_hyp_vcpu * vcpu = & selftest_vcpu ;
1152+ u64 phys = hyp_virt_to_phys (virt );
1153+ u64 ipa [2 ] = { selftest_ipa (), selftest_ipa () + PAGE_SIZE };
1154+
1155+ host_lock_component ();
1156+ WARN_ON (__host_check_page_state_range (phys , size , selftest_state .host ));
1157+ host_unlock_component ();
1158+
1159+ hyp_lock_component ();
1160+ WARN_ON (__hyp_check_page_state_range (phys , size , selftest_state .hyp ));
1161+ hyp_unlock_component ();
1162+
1163+ guest_lock_component (& selftest_vm );
1164+ WARN_ON (__guest_check_page_state_range (vcpu , ipa [0 ], size , selftest_state .guest [0 ]));
1165+ WARN_ON (__guest_check_page_state_range (vcpu , ipa [1 ], size , selftest_state .guest [1 ]));
1166+ guest_unlock_component (& selftest_vm );
1167+ }
1168+
1169+ #define assert_transition_res (res , fn , ...) \
1170+ do { \
1171+ WARN_ON(fn(__VA_ARGS__) != res); \
1172+ assert_page_state(); \
1173+ } while (0)
1174+
1175+ void pkvm_ownership_selftest (void * base )
1176+ {
1177+ enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_RWX ;
1178+ void * virt = hyp_alloc_pages (& host_s2_pool , 0 );
1179+ struct pkvm_hyp_vcpu * vcpu = & selftest_vcpu ;
1180+ struct pkvm_hyp_vm * vm = & selftest_vm ;
1181+ u64 phys , size , pfn , gfn ;
1182+
1183+ WARN_ON (!virt );
1184+ selftest_page = hyp_virt_to_page (virt );
1185+ selftest_page -> refcount = 0 ;
1186+ init_selftest_vm (base );
1187+
1188+ size = PAGE_SIZE << selftest_page -> order ;
1189+ phys = hyp_virt_to_phys (virt );
1190+ pfn = hyp_phys_to_pfn (phys );
1191+ gfn = hyp_phys_to_pfn (selftest_ipa ());
1192+
1193+ selftest_state .host = PKVM_NOPAGE ;
1194+ selftest_state .hyp = PKVM_PAGE_OWNED ;
1195+ selftest_state .guest [0 ] = selftest_state .guest [1 ] = PKVM_NOPAGE ;
1196+ assert_page_state ();
1197+ assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1198+ assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
1199+ assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
1200+ assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1201+ assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
1202+ assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1203+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1204+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1205+
1206+ selftest_state .host = PKVM_PAGE_OWNED ;
1207+ selftest_state .hyp = PKVM_NOPAGE ;
1208+ assert_transition_res (0 , __pkvm_hyp_donate_host , pfn , 1 );
1209+ assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1210+ assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
1211+ assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
1212+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1213+ assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1214+
1215+ selftest_state .host = PKVM_PAGE_SHARED_OWNED ;
1216+ selftest_state .hyp = PKVM_PAGE_SHARED_BORROWED ;
1217+ assert_transition_res (0 , __pkvm_host_share_hyp , pfn );
1218+ assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
1219+ assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1220+ assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1221+ assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1222+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1223+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1224+
1225+ assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
1226+ assert_transition_res (0 , hyp_pin_shared_mem , virt , virt + size );
1227+ hyp_unpin_shared_mem (virt , virt + size );
1228+ WARN_ON (hyp_page_count (virt ) != 1 );
1229+ assert_transition_res (- EBUSY , __pkvm_host_unshare_hyp , pfn );
1230+ assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
1231+ assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1232+ assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1233+ assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1234+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1235+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1236+
1237+ hyp_unpin_shared_mem (virt , virt + size );
1238+ assert_page_state ();
1239+ WARN_ON (hyp_page_count (virt ));
1240+
1241+ selftest_state .host = PKVM_PAGE_OWNED ;
1242+ selftest_state .hyp = PKVM_NOPAGE ;
1243+ assert_transition_res (0 , __pkvm_host_unshare_hyp , pfn );
1244+
1245+ selftest_state .host = PKVM_PAGE_SHARED_OWNED ;
1246+ selftest_state .hyp = PKVM_NOPAGE ;
1247+ assert_transition_res (0 , __pkvm_host_share_ffa , pfn , 1 );
1248+ assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1249+ assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1250+ assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
1251+ assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
1252+ assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1253+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1254+ assert_transition_res (- ENOENT , __pkvm_host_unshare_guest , gfn , vm );
1255+ assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1256+
1257+ selftest_state .host = PKVM_PAGE_OWNED ;
1258+ selftest_state .hyp = PKVM_NOPAGE ;
1259+ assert_transition_res (0 , __pkvm_host_unshare_ffa , pfn , 1 );
1260+ assert_transition_res (- EPERM , __pkvm_host_unshare_ffa , pfn , 1 );
1261+
1262+ selftest_state .host = PKVM_PAGE_SHARED_OWNED ;
1263+ selftest_state .guest [0 ] = PKVM_PAGE_SHARED_BORROWED ;
1264+ assert_transition_res (0 , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1265+ assert_transition_res (- EPERM , __pkvm_host_share_guest , pfn , gfn , vcpu , prot );
1266+ assert_transition_res (- EPERM , __pkvm_host_share_ffa , pfn , 1 );
1267+ assert_transition_res (- EPERM , __pkvm_host_donate_hyp , pfn , 1 );
1268+ assert_transition_res (- EPERM , __pkvm_host_share_hyp , pfn );
1269+ assert_transition_res (- EPERM , __pkvm_host_unshare_hyp , pfn );
1270+ assert_transition_res (- EPERM , __pkvm_hyp_donate_host , pfn , 1 );
1271+ assert_transition_res (- EPERM , hyp_pin_shared_mem , virt , virt + size );
1272+
1273+ selftest_state .guest [1 ] = PKVM_PAGE_SHARED_BORROWED ;
1274+ assert_transition_res (0 , __pkvm_host_share_guest , pfn , gfn + 1 , vcpu , prot );
1275+ WARN_ON (hyp_virt_to_page (virt )-> host_share_guest_count != 2 );
1276+
1277+ selftest_state .guest [0 ] = PKVM_NOPAGE ;
1278+ assert_transition_res (0 , __pkvm_host_unshare_guest , gfn , vm );
1279+
1280+ selftest_state .guest [1 ] = PKVM_NOPAGE ;
1281+ selftest_state .host = PKVM_PAGE_OWNED ;
1282+ assert_transition_res (0 , __pkvm_host_unshare_guest , gfn + 1 , vm );
1283+
1284+ selftest_state .host = PKVM_NOPAGE ;
1285+ selftest_state .hyp = PKVM_PAGE_OWNED ;
1286+ assert_transition_res (0 , __pkvm_host_donate_hyp , pfn , 1 );
1287+
1288+ selftest_page -> refcount = 1 ;
1289+ hyp_put_page (& host_s2_pool , virt );
1290+ }
1291+ #endif
0 commit comments