@@ -1069,6 +1069,367 @@ static int test_timeout_fault_nested_servers(env_t env)
10691069/* this test is disabled for the same reason as TIMEOUTFAULT0002 */
10701070DEFINE_TEST (TIMEOUTFAULT0003 , "Nested timeout fault" , test_timeout_fault_nested_servers , config_set (CONFIG_KERNEL_MCS ))
10711071
1072+ /* Test of invalid SC and no SC faults */
1073+
1074+ typedef int request_fn (void * );
1075+
1076+ static int timeout_fault_generic_server_fn (seL4_CPtr ep , seL4_CPtr ro )
1077+ {
1078+ api_nbsend_recv (ep , seL4_MessageInfo_new (0 , 0 , 0 , 0 ), ep , NULL , ro );
1079+ while (true) {
1080+ request_fn * request = (request_fn * )seL4_GetMR (0 );
1081+ void * request_data = (void * )seL4_GetMR (1 );
1082+ int result = request (request_data );
1083+ seL4_SetMR (0 , result );
1084+ api_reply_recv (ep , seL4_MessageInfo_new (0 , 0 , 0 , 1 ), NULL , ro );
1085+ }
1086+ }
1087+
1088+ static int timeout_fault_infinite_loop_request (void * data )
1089+ {
1090+ ZF_LOGD ("Entering infinite loop" );
1091+ while (true);
1092+ }
1093+
1094+ static int timeout_fault_donate_client_fn (seL4_CPtr ep , int donate )
1095+ {
1096+ seL4_MessageInfo_t info = seL4_MessageInfo_new (0 , 0 , 0 , 2 );
1097+ seL4_SetMR (0 , (seL4_Word )timeout_fault_infinite_loop_request );
1098+ seL4_SetMR (1 , 0 );
1099+ if (donate ) {
1100+ ZF_LOGD ("Client call" );
1101+ seL4_Call (ep , info );
1102+ } else {
1103+ ZF_LOGD ("Client send" );
1104+ seL4_Send (ep , info );
1105+ }
1106+ ZF_LOGD ("Client return" );
1107+ return 0 ;
1108+ }
1109+
1110+ static int catch_invalid_sc (seL4_CPtr tfep , seL4_Word expected_badge , seL4_Word expected_data ,
1111+ seL4_Word expected_reason , env_t env )
1112+ {
1113+ seL4_Word badge ;
1114+ seL4_CPtr server_reply = vka_alloc_reply_leaky (& env -> vka );
1115+
1116+ /* wait for timeout fault */
1117+ ZF_LOGD ("Wait for tf" );
1118+ seL4_MessageInfo_t info = api_recv (tfep , & badge , server_reply );
1119+ test_eq (badge , expected_badge );
1120+ #ifdef CONFIG_KERNEL_MCS
1121+ test_check (seL4_isTimeoutFault_tag (info ));
1122+ test_eq (seL4_MessageInfo_get_length (info ), (seL4_Word ) seL4_Timeout_Length );
1123+ test_eq (seL4_GetMR (seL4_Timeout_Data ), expected_data );
1124+ test_eq (seL4_GetMR (seL4_Timeout_Reason ), expected_reason );
1125+ #endif
1126+
1127+ return 0 ;
1128+ }
1129+
1130+ static int test_timeout_fault_no_donated_sc (env_t env )
1131+ {
1132+ helper_thread_t client , server ;
1133+ sel4utils_checkpoint_t server_cp ;
1134+
1135+ seL4_Word client_data = 1 ;
1136+ seL4_Word server_badge = 2 ;
1137+
1138+ seL4_CPtr server_ep = vka_alloc_endpoint_leaky (& env -> vka );
1139+ seL4_CPtr tfep = vka_alloc_endpoint_leaky (& env -> vka );
1140+ seL4_CPtr server_ro = vka_alloc_reply_leaky (& env -> vka );
1141+
1142+ /* create server */
1143+ int error = create_passive_thread_with_tfep (env , & server , tfep , server_badge ,
1144+ (helper_fn_t ) timeout_fault_generic_server_fn , server_ep ,
1145+ server_ro , 0 , 0 , & server_cp );
1146+ test_eq (error , 0 );
1147+
1148+ /* create non-donating client */
1149+ create_helper_thread (env , & client );
1150+
1151+ /* Run the helper */
1152+ start_helper (env , & client , (helper_fn_t ) timeout_fault_donate_client_fn , server_ep , 0 , 0 , 0 );
1153+
1154+ #ifdef CONFIG_KERNEL_MCS
1155+ /* Catch the fault */
1156+ catch_invalid_sc (tfep , server_badge , 0 , seL4_Timeout_NoSC , env );
1157+ #endif
1158+
1159+ return sel4test_get_result ();
1160+ }
1161+ DEFINE_TEST (TIMEOUTFAULT0004 , "Fault on no donated SC" , test_timeout_fault_no_donated_sc , config_set (CONFIG_KERNEL_MCS ))
1162+
1163+ typedef struct {
1164+ env_t env ;
1165+ seL4_CPtr ep ;
1166+ int replace_sc ;
1167+ } create_client_request_t ;
1168+
1169+ static int create_client_request (void * data )
1170+ {
1171+ create_client_request_t * request = data ;
1172+
1173+ /* Create a new client */
1174+ helper_thread_t client ;
1175+ create_helper_thread (request -> env , & client );
1176+ start_helper (request -> env , & client , (helper_fn_t ) timeout_fault_donate_client_fn , request -> ep , 1 , 0 , 0 );
1177+
1178+ /* Yield to the client to let it call */
1179+ seL4_Yield ();
1180+
1181+ /* Remove existing SC */
1182+ int error = api_sc_unbind (client .thread .sched_context .cptr );
1183+ test_eq (error , 0 );
1184+
1185+ /* Replace with unconfigured SC */
1186+ if (request -> replace_sc ) {
1187+ seL4_CPtr sc = vka_alloc_sched_context_leaky (& request -> env -> vka );
1188+ error = api_sc_bind (sc , client .thread .tcb .cptr );
1189+ test_eq (error , 0 );
1190+ }
1191+
1192+ return 0 ;
1193+ }
1194+
1195+ static void call_create_client_request (env_t env , seL4_CPtr server_ep , int replace_sc )
1196+ {
1197+ create_client_request_t request = {
1198+ .env = env ,
1199+ .ep = server_ep ,
1200+ .replace_sc = replace_sc ,
1201+ };
1202+ seL4_SetMR (0 , (seL4_Word )create_client_request );
1203+ seL4_SetMR (1 , (seL4_Word )(& request ));
1204+ seL4_Call (server_ep , seL4_MessageInfo_new (0 , 0 , 0 , 2 ));
1205+ }
1206+
1207+ static int test_timeout_fault_client_sc_removed (env_t env )
1208+ {
1209+ helper_thread_t server ;
1210+ sel4utils_checkpoint_t server_cp ;
1211+
1212+ seL4_Word client_data = 1 ;
1213+ seL4_Word server_badge = 2 ;
1214+
1215+ seL4_CPtr server_ep = vka_alloc_endpoint_leaky (& env -> vka );
1216+ seL4_CPtr tfep = vka_alloc_endpoint_leaky (& env -> vka );
1217+ seL4_CPtr server_ro = vka_alloc_reply_leaky (& env -> vka );
1218+
1219+ /* create server */
1220+ int error = create_passive_thread_with_tfep (env , & server , tfep , server_badge ,
1221+ (helper_fn_t ) timeout_fault_generic_server_fn , server_ep ,
1222+ server_ro , 0 , 0 , & server_cp );
1223+ test_eq (error , 0 );
1224+
1225+ /* Use server to create client to ensure client is blocked on the
1226+ * endpoint when its SC is removed. */
1227+ ZF_LOGD ("Creating client from server" );
1228+ /* Yield to ensure maximum time in donated SC */
1229+ seL4_Yield ();
1230+ call_create_client_request (env , server_ep , 0 );
1231+
1232+ #ifdef CONFIG_KERNEL_MCS
1233+ /* Catch the fault */
1234+ catch_invalid_sc (tfep , server_badge , 0 , seL4_Timeout_NoSC , env );
1235+ #endif
1236+
1237+ return sel4test_get_result ();
1238+ }
1239+ DEFINE_TEST (TIMEOUTFAULT0005 , "Fault on client SC removed" , test_timeout_fault_client_sc_removed ,
1240+ config_set (CONFIG_KERNEL_MCS ))
1241+
1242+
1243+ static int timeout_fault_spinning_client (void )
1244+ {
1245+ while (1 ) {}
1246+ return 0 ;
1247+ }
1248+
1249+ static int test_timeout_fault_sc_removed (env_t env )
1250+ {
1251+ helper_thread_t thread ;
1252+
1253+ seL4_Word badge = 1 ;
1254+
1255+ seL4_CPtr tfep = vka_alloc_endpoint_leaky (& env -> vka );
1256+
1257+ /* create thread */
1258+ create_helper_thread (env , & thread );
1259+ create_and_set_tfep (env , & thread , tfep , badge );
1260+ start_helper (env , & thread , (helper_fn_t ) timeout_fault_spinning_client , 0 , 0 , 0 , 0 );
1261+
1262+ /* Remove the SC from the thread */
1263+ int error = api_sc_unbind (thread .thread .sched_context .cptr );
1264+ test_eq (error , 0 );
1265+
1266+ #ifdef CONFIG_KERNEL_MCS
1267+ /* Catch the fault */
1268+ catch_invalid_sc (tfep , badge , 0 , seL4_Timeout_NoSC , env );
1269+ #endif
1270+
1271+ return sel4test_get_result ();
1272+ }
1273+ DEFINE_TEST (TIMEOUTFAULT0006 , "Fault on SC removed while running" , test_timeout_fault_sc_removed ,
1274+ config_set (CONFIG_KERNEL_MCS ))
1275+
1276+ void
1277+ timeout_fault_sc_remove_server_fn (seL4_CPtr ep , env_t env , seL4_CPtr ro , seL4_CPtr ntfn )
1278+ {
1279+ /* signal to initialiser that we are done, and wait for a message from
1280+ * the client */
1281+ api_nbsend_recv (ep , seL4_MessageInfo_new (0 , 0 , 0 , 0 ), ep , NULL , ro );
1282+ /* Signal to indicate entry into server */
1283+ seL4_Signal (ntfn );
1284+ /* spin, this will use up all of the clients budget */
1285+ while (true);
1286+ /* we should not get here, as a timeout fault should have been raised
1287+ * and the handler will reset us */
1288+ ZF_LOGF ("Should not get here" );
1289+ }
1290+
1291+ static int test_timeout_fault_donated_sc_removed (env_t env )
1292+ {
1293+ helper_thread_t client , server ;
1294+ sel4utils_checkpoint_t server_cp ;
1295+
1296+ seL4_Word client_data = 1 ;
1297+ seL4_Word server_badge = 2 ;
1298+
1299+ seL4_CPtr server_ep = vka_alloc_endpoint_leaky (& env -> vka );
1300+ seL4_CPtr tfep = vka_alloc_endpoint_leaky (& env -> vka );
1301+ seL4_CPtr server_ro = vka_alloc_reply_leaky (& env -> vka );
1302+ seL4_CPtr server_ntfn = vka_alloc_notification_leaky (& env -> vka );
1303+
1304+ /* create server */
1305+ ZF_LOGD ("Start server" );
1306+ int error = create_passive_thread_with_tfep (env , & server , tfep , server_badge ,
1307+ (helper_fn_t ) timeout_fault_sc_remove_server_fn , server_ep ,
1308+ (seL4_Word )env , server_ro , server_ntfn , & server_cp );
1309+ test_eq (error , 0 );
1310+
1311+ /* create donating client */
1312+ ZF_LOGD ("Start client" );
1313+ create_helper_thread (env , & client );
1314+ start_helper (env , & client , (helper_fn_t ) timeout_fault_donate_client_fn , server_ep , 1 , 0 , 0 );
1315+
1316+ /* Wait for server to get donated SC. */
1317+ ZF_LOGD ("Wait for server" );
1318+ seL4_Wait (server_ntfn , NULL );
1319+
1320+ /* Remove SC from client */
1321+ error = api_sc_unbind (client .thread .sched_context .cptr );
1322+ test_eq (error , 0 );
1323+
1324+ #ifdef CONFIG_KERNEL_MCS
1325+ /* Catch the fault from the server */
1326+ catch_invalid_sc (tfep , server_badge , 0 , seL4_Timeout_NoSC , env );
1327+ #endif
1328+
1329+ return sel4test_get_result ();
1330+ }
1331+ DEFINE_TEST (TIMEOUTFAULT0007 , "Fault on donated SC removed while running" , test_timeout_fault_donated_sc_removed ,
1332+ config_set (CONFIG_KERNEL_MCS ))
1333+
1334+ static int test_timeout_fault_reply_without_sc_return (env_t env )
1335+ {
1336+ helper_thread_t client , proxy , server ;
1337+ sel4utils_checkpoint_t proxy_cp , server_cp ;
1338+
1339+ seL4_Word client_data = 1 ;
1340+ seL4_Word server_badge = 2 ;
1341+ seL4_Word proxy_badge = 3 ;
1342+ seL4_Word client_badge = 4 ;
1343+
1344+ seL4_CPtr server_ep = vka_alloc_endpoint_leaky (& env -> vka );
1345+ seL4_CPtr proxy_ep = vka_alloc_endpoint_leaky (& env -> vka );
1346+ seL4_CPtr tfep = vka_alloc_endpoint_leaky (& env -> vka );
1347+ seL4_CPtr server_ro = vka_alloc_reply_leaky (& env -> vka );
1348+ seL4_CPtr proxy_ro = vka_alloc_reply_leaky (& env -> vka );
1349+
1350+ /* create server */
1351+ ZF_LOGD ("Start server" );
1352+ int error = create_passive_thread_with_tfep (env , & server , tfep , server_badge ,
1353+ (helper_fn_t ) timeout_fault_generic_server_fn , server_ep ,
1354+ server_ro , 0 , 0 , & server_cp );
1355+ test_eq (error , 0 );
1356+
1357+ /* create proxy */
1358+ /* The proxy is used to ensure that if the proxy prematurely replies
1359+ * to the client before it is returned an SC, the client still
1360+ * faults */
1361+ error = create_passive_thread_with_tfep (env , & proxy , tfep , proxy_badge , (helper_fn_t ) timeout_fault_proxy_fn , proxy_ep ,
1362+ server_ep , proxy_ro , 0 , & proxy_cp );
1363+ test_eq (error , 0 );
1364+
1365+ /* create donating client */
1366+ ZF_LOGD ("Start client" );
1367+ create_helper_thread (env , & client );
1368+
1369+ error = api_sched_ctrl_configure (simple_get_sched_ctrl (& env -> simple , 0 ),
1370+ client .thread .sched_context .cptr ,
1371+ 0.1 * US_IN_S , 0.5 * US_IN_S , 0 , client_data );
1372+ test_eq (error , 0 );
1373+
1374+ create_and_set_tfep (env , & client , tfep , client_badge );
1375+ start_helper (env , & client , (helper_fn_t ) timeout_fault_donate_client_fn , proxy_ep , 1 , 0 , 0 );
1376+
1377+ #ifdef CONFIG_KERNEL_MCS
1378+ /* Catch the fault from the server */
1379+ ZF_LOGD ("Wait for server to exhaust SC" );
1380+ catch_invalid_sc (tfep , server_badge , client_data , seL4_Timeout_Exhausted , env );
1381+ #endif
1382+
1383+ /* Reply to the client */
1384+ ZF_LOGD ("Resume client without SC" );
1385+ seL4_Send (proxy_ro , seL4_MessageInfo_new (0 , 0 , 0 , 0 ));
1386+
1387+ #ifdef CONFIG_KERNEL_MCS
1388+ /* Catch the client fault */
1389+ ZF_LOGD ("Catch client fault" );
1390+ catch_invalid_sc (tfep , client_badge , 0 , seL4_Timeout_NoSC , env );
1391+ #endif
1392+
1393+ return sel4test_get_result ();
1394+ }
1395+ DEFINE_TEST (TIMEOUTFAULT0008 , "Fault on reply without SC return" , test_timeout_fault_reply_without_sc_return ,
1396+ config_set (CONFIG_KERNEL_MCS ))
1397+
1398+ static int test_timeout_fault_inactive_sc_donation (env_t env )
1399+ {
1400+ helper_thread_t server ;
1401+ sel4utils_checkpoint_t server_cp ;
1402+
1403+ seL4_Word client_data = 1 ;
1404+ seL4_Word server_badge = 2 ;
1405+
1406+ seL4_CPtr server_ep = vka_alloc_endpoint_leaky (& env -> vka );
1407+ seL4_CPtr tfep = vka_alloc_endpoint_leaky (& env -> vka );
1408+ seL4_CPtr server_ro = vka_alloc_reply_leaky (& env -> vka );
1409+
1410+ /* create server */
1411+ int error = create_passive_thread_with_tfep (env , & server , tfep , server_badge ,
1412+ (helper_fn_t ) timeout_fault_generic_server_fn , server_ep ,
1413+ server_ro , 0 , 0 , & server_cp );
1414+ test_eq (error , 0 );
1415+
1416+ /* Use server to create client to ensure client is blocked on the
1417+ * endpoint when its SC is replaced. */
1418+ ZF_LOGD ("Creating client from server" );
1419+ /* Yield to ensure maximum time in donated SC */
1420+ seL4_Yield ();
1421+ call_create_client_request (env , server_ep , 1 );
1422+
1423+ #ifdef CONFIG_KERNEL_MCS
1424+ /* Catch the fault */
1425+ catch_invalid_sc (tfep , server_badge , 0 , seL4_Timeout_Unconfigured , env );
1426+ #endif
1427+
1428+ return sel4test_get_result ();
1429+ }
1430+ DEFINE_TEST (TIMEOUTFAULT0009 , "Fault on donation of unconfigured SC" , test_timeout_fault_inactive_sc_donation ,
1431+ config_set (CONFIG_KERNEL_MCS ))
1432+
10721433static void vm_enter (void )
10731434{
10741435#ifdef CONFIG_VTX
0 commit comments