@@ -921,7 +921,6 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu,
921
921
if (page -> host_share_guest_count )
922
922
break ;
923
923
/* Only host to np-guest multi-sharing is tolerated */
924
- WARN_ON (1 );
925
924
fallthrough ;
926
925
default :
927
926
ret = - EPERM ;
@@ -1093,3 +1092,200 @@ int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu)
1093
1092
1094
1093
return 0 ;
1095
1094
}
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