Skip to content

Commit f8a9475

Browse files
committed
mcs: Add tests for invalid SC faults
TIMEOUTFAULT0004: Fault on no donated SC When a passive thread receives an IPC and the sender has not used seL4_Call, the sender's SC is not donated and the receiver faults to indicate that it is running without a SC. TIMEOUTFAULT0005: Fault on client SC removed When a passive thread receives an IPC and the sender's SC has been removed while it is blocked, receiver faults to indicate that it is running without a SC. TIMEOUTFAULT0006: Fault on SC removed while running When a thread with an SC is running and its SC is removed, that thread faults. TIMEOUTFAULT0007: Fault on donated SC removed while running When a passive thread is running on a donated SC and that SC is unbound, the passive thread faults as it no longer has an SC. TIMEOUTFAULT0008: Fault on reply without SC return When a client makes a call that results in a nested call and a monitor replies to the first call, the client is not returned its SC, as such it faults. TIMEOUTFAULT0009: Fault on donation of unconfigured SC When a passive thread receives an IPC and the sender's SC has been replaced with an unconfigured SC while it is blocked, receiver faults to indicate that it is running with an unconfigured SC. Signed-off-by: Curtis Millar <curtis.millar@data61.csiro.au>
1 parent cf0b9c3 commit f8a9475

1 file changed

Lines changed: 361 additions & 0 deletions

File tree

apps/sel4test-tests/src/tests/faults.c

Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
10701070
DEFINE_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+
10721433
static void vm_enter(void)
10731434
{
10741435
#ifdef CONFIG_VTX

0 commit comments

Comments
 (0)