1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <assert.h> 14#include <stdio.h> 15#include <stdlib.h> 16#include <sel4/sel4.h> 17#include <vka/object.h> 18 19#include "../helpers.h" 20 21#define MIN_LENGTH 0 22#define MAX_LENGTH (seL4_MsgMaxLength) 23 24#define FOR_EACH_LENGTH(len_var) \ 25 for(int len_var = MIN_LENGTH; len_var <= MAX_LENGTH; len_var++) 26 27typedef int (*test_func_t)(seL4_Word /* endpoint */, seL4_Word /* seed */, seL4_Word /* reply */, 28 seL4_CPtr /* extra */); 29 30static int send_func(seL4_Word endpoint, seL4_Word seed, seL4_Word reply, seL4_Word extra) 31{ 32 FOR_EACH_LENGTH(length) { 33 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, length); 34 for (int i = 0; i < length; i++) { 35 seL4_SetMR(i, seed); 36 seed++; 37 } 38 seL4_Send(endpoint, tag); 39 } 40 41 return SUCCESS; 42} 43 44static int nbsend_func(seL4_Word endpoint, seL4_Word seed, seL4_Word reply, seL4_Word extra) 45{ 46 FOR_EACH_LENGTH(length) { 47 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, length); 48 for (int i = 0; i < length; i++) { 49 seL4_SetMR(i, seed); 50 seed++; 51 } 52 seL4_NBSend(endpoint, tag); 53 } 54 55 return SUCCESS; 56} 57 58static int call_func(seL4_Word endpoint, seL4_Word seed, seL4_Word reply, seL4_Word extra) 59{ 60 test_result_t result = SUCCESS; 61 FOR_EACH_LENGTH(length) { 62 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, length); 63 64 /* Construct a message. */ 65 for (int i = 0; i < length; i++) { 66 seL4_SetMR(i, seed); 67 seed++; 68 } 69 70 tag = seL4_Call(endpoint, tag); 71 72 seL4_Word actual_len = length; 73 /* Sanity check the received message. */ 74 if (actual_len <= seL4_MsgMaxLength) { 75 if (actual_len != seL4_MessageInfo_get_length(tag)) { 76 result = FAILURE; 77 } 78 } else { 79 actual_len = seL4_MsgMaxLength; 80 } 81 82 for (int i = 0; i < actual_len; i++) { 83 seL4_Word mr = seL4_GetMR(i); 84 if (mr != seed) { 85 result = FAILURE; 86 } 87 seed++; 88 } 89 } 90 91 return result; 92} 93 94static int wait_func(seL4_Word endpoint, seL4_Word seed, seL4_Word reply, seL4_Word extra) 95{ 96 test_result_t result = SUCCESS; 97 FOR_EACH_LENGTH(length) { 98 seL4_MessageInfo_t tag; 99 seL4_Word sender_badge = 0; 100 101 tag = api_recv(endpoint, &sender_badge, reply); 102 seL4_Word actual_len = length; 103 if (actual_len <= seL4_MsgMaxLength) { 104 if (actual_len != seL4_MessageInfo_get_length(tag)) { 105 result = FAILURE; 106 } 107 } else { 108 actual_len = seL4_MsgMaxLength; 109 } 110 111 for (int i = 0; i < actual_len; i++) { 112 seL4_Word mr = seL4_GetMR(i); 113 if (mr != seed) { 114 result = FAILURE; 115 } 116 seed++; 117 } 118 } 119 120 return result; 121} 122 123static int nbwait_func(seL4_Word endpoint, seL4_Word seed, seL4_Word reply, seL4_Word nbwait_should_wait) 124{ 125 if (!nbwait_should_wait) { 126 return SUCCESS; 127 } 128 129 test_result_t result = SUCCESS; 130 FOR_EACH_LENGTH(length) { 131 seL4_MessageInfo_t tag; 132 seL4_Word sender_badge = 0; 133 134 tag = api_recv(endpoint, &sender_badge, reply); 135 seL4_Word actual_len = length; 136 if (actual_len <= seL4_MsgMaxLength) { 137 if (actual_len != seL4_MessageInfo_get_length(tag)) { 138 result = FAILURE; 139 } 140 } else { 141 actual_len = seL4_MsgMaxLength; 142 } 143 144 for (int i = 0; i < actual_len; i++) { 145 seL4_Word mr = seL4_GetMR(i); 146 if (mr != seed) { 147 result = FAILURE; 148 } 149 seed++; 150 } 151 } 152 153 return result; 154} 155 156static int replywait_func(seL4_Word endpoint, seL4_Word seed, seL4_CPtr reply, seL4_Word extra) 157{ 158 int first = 1; 159 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); 160 161 test_result_t result = SUCCESS; 162 FOR_EACH_LENGTH(length) { 163 seL4_Word sender_badge = 0; 164 165 /* First reply/wait can't reply. */ 166 if (first) { 167#ifdef CONFIG_KERNEL_MCS 168 tag = seL4_NBSendRecv(endpoint, tag, endpoint, &sender_badge, reply); 169#else 170 tag = seL4_Recv(endpoint, &sender_badge); 171#endif 172 first = 0; 173 } else { 174 tag = api_reply_recv(endpoint, tag, &sender_badge, reply); 175 } 176 177 seL4_Word actual_len = length; 178 /* Sanity check the received message. */ 179 if (actual_len <= seL4_MsgMaxLength) { 180 if (actual_len != seL4_MessageInfo_get_length(tag)) { 181 result = FAILURE; 182 } 183 } else { 184 actual_len = seL4_MsgMaxLength; 185 } 186 187 for (int i = 0; i < actual_len; i++) { 188 seL4_Word mr = seL4_GetMR(i); 189 if (mr != seed) { 190 result = FAILURE; 191 } 192 seed++; 193 } 194 /* Seed will have changed more if the message was truncated. */ 195 for (int i = actual_len; i < length; i++) { 196 seed++; 197 } 198 199 /* Construct a reply. */ 200 for (int i = 0; i < actual_len; i++) { 201 seL4_SetMR(i, seed); 202 seed++; 203 } 204 } 205 206 /* Need to do one last reply to match call. */ 207 api_reply(reply, tag); 208 209 return result; 210} 211 212static int reply_and_wait_func(seL4_Word endpoint, seL4_Word seed, seL4_CPtr reply, seL4_Word unused) 213{ 214 int first = 1; 215 216 test_result_t result = SUCCESS; 217 seL4_MessageInfo_t tag; 218 FOR_EACH_LENGTH(length) { 219 seL4_Word sender_badge = 0; 220 221 /* First reply/wait can't reply. */ 222 if (!first) { 223 api_reply(reply, tag); 224 } else { 225 first = 0; 226 } 227 228 tag = api_recv(endpoint, &sender_badge, reply); 229 230 seL4_Word actual_len = length; 231 /* Sanity check the received message. */ 232 if (actual_len <= seL4_MsgMaxLength) { 233 if (actual_len != seL4_MessageInfo_get_length(tag)) { 234 result = FAILURE; 235 } 236 } else { 237 actual_len = seL4_MsgMaxLength; 238 } 239 240 for (int i = 0; i < actual_len; i++) { 241 seL4_Word mr = seL4_GetMR(i); 242 if (mr != seed) { 243 result = FAILURE; 244 } 245 seed++; 246 } 247 /* Seed will have changed more if the message was truncated. */ 248 for (int i = actual_len; i < length; i++) { 249 seed++; 250 } 251 252 /* Construct a reply. */ 253 for (int i = 0; i < actual_len; i++) { 254 seL4_SetMR(i, seed); 255 seed++; 256 } 257 } 258 259 /* Need to do one last reply to match call. */ 260 api_reply(reply, tag); 261 262 return result; 263} 264 265#ifdef CONFIG_KERNEL_MCS 266/* this function is expected to talk to another version of itself, second implies 267 * that this is the second to be executed */ 268static int nbsendrecv_func(seL4_Word endpoint, seL4_Word seed, seL4_Word reply, seL4_Word unused) 269{ 270 FOR_EACH_LENGTH(length) { 271 api_nbsend_recv(endpoint, seL4_MessageInfo_new(0, 0, 0, MAX_LENGTH), endpoint, NULL, reply); 272 } 273 274 /* signal we're done to hanging second thread */ 275 seL4_NBSend(endpoint, seL4_MessageInfo_new(0, 0, 0, MAX_LENGTH)); 276 277 return SUCCESS; 278} 279#endif /* CONFIG_KERNEL_MCS */ 280 281static int test_ipc_pair(env_t env, test_func_t fa, test_func_t fb, bool inter_as, seL4_Word nr_cores) 282{ 283 helper_thread_t thread_a, thread_b; 284 vka_t *vka = &env->vka; 285 286 UNUSED int error; 287 seL4_CPtr ep = vka_alloc_endpoint_leaky(vka); 288 seL4_Word start_number = 0xabbacafe; 289 290 seL4_CPtr a_reply = vka_alloc_reply_leaky(vka); 291 seL4_CPtr b_reply = vka_alloc_reply_leaky(vka); 292 293 /* Test sending messages of varying lengths. */ 294 /* Please excuse the awful indending here. */ 295 for (int core_a = 0; core_a < nr_cores; core_a++) { 296 for (int core_b = 0; core_b < nr_cores; core_b++) { 297 for (int sender_prio = 98; sender_prio <= 102; sender_prio++) { 298 for (int waiter_prio = 100; waiter_prio <= 100; waiter_prio++) { 299 for (int sender_first = 0; sender_first <= 1; sender_first++) { 300 ZF_LOGD("%d %s %d\n", 301 sender_prio, sender_first ? "->" : "<-", waiter_prio); 302 seL4_Word thread_a_arg0, thread_b_arg0; 303 seL4_CPtr thread_a_reply, thread_b_reply; 304 305 if (inter_as) { 306 create_helper_process(env, &thread_a); 307 308 cspacepath_t path; 309 vka_cspace_make_path(&env->vka, ep, &path); 310 thread_a_arg0 = sel4utils_copy_path_to_process(&thread_a.process, path); 311 assert(thread_a_arg0 != -1); 312 313 create_helper_process(env, &thread_b); 314 thread_b_arg0 = sel4utils_copy_path_to_process(&thread_b.process, path); 315 assert(thread_b_arg0 != -1); 316 317 if (config_set(CONFIG_KERNEL_MCS)) { 318 thread_a_reply = sel4utils_copy_cap_to_process(&thread_a.process, vka, a_reply); 319 thread_b_reply = sel4utils_copy_cap_to_process(&thread_b.process, vka, b_reply); 320 } 321 } else { 322 create_helper_thread(env, &thread_a); 323 create_helper_thread(env, &thread_b); 324 thread_a_arg0 = ep; 325 thread_b_arg0 = ep; 326 thread_a_reply = a_reply; 327 thread_b_reply = b_reply; 328 } 329 330 set_helper_priority(env, &thread_a, sender_prio); 331 set_helper_priority(env, &thread_b, waiter_prio); 332 333 set_helper_affinity(env, &thread_a, core_a); 334 set_helper_affinity(env, &thread_b, core_b); 335 336 /* Set the flag for nbwait_func that tells it whether or not it really 337 * should wait. */ 338 int nbwait_should_wait; 339 nbwait_should_wait = 340 (sender_prio < waiter_prio); 341 342 /* Threads are enqueued at the head of the scheduling queue, so the 343 * thread enqueued last will be run first, for a given priority. */ 344 if (sender_first) { 345 start_helper(env, &thread_b, (helper_fn_t) fb, thread_b_arg0, start_number, 346 thread_b_reply, nbwait_should_wait); 347 start_helper(env, &thread_a, (helper_fn_t) fa, thread_a_arg0, start_number, 348 thread_a_reply, nbwait_should_wait); 349 } else { 350 start_helper(env, &thread_a, (helper_fn_t) fa, thread_a_arg0, start_number, 351 thread_a_reply, nbwait_should_wait); 352 start_helper(env, &thread_b, (helper_fn_t) fb, thread_b_arg0, start_number, 353 thread_b_reply, nbwait_should_wait); 354 } 355 356 test_result_t res = wait_for_helper(&thread_a); 357 test_eq(res, SUCCESS); 358 res = wait_for_helper(&thread_b); 359 test_eq(res, SUCCESS); 360 361 cleanup_helper(env, &thread_a); 362 cleanup_helper(env, &thread_b); 363 364 start_number += 0x71717171; 365 } 366 } 367 } 368 } 369 } 370 371 error = cnode_delete(env, ep); 372 test_error_eq(error, seL4_NoError); 373 return sel4test_get_result(); 374} 375 376static int test_send_wait(env_t env) 377{ 378 return test_ipc_pair(env, send_func, wait_func, false, env->cores); 379} 380DEFINE_TEST(IPC0001, "Test SMP seL4_Send + seL4_Recv", test_send_wait, true) 381 382static int 383test_call_replywait(env_t env) 384{ 385 return test_ipc_pair(env, call_func, replywait_func, false, env->cores); 386} 387DEFINE_TEST(IPC0002, "Test SMP seL4_Call + seL4_ReplyRecv", test_call_replywait, true) 388 389static int 390test_call_reply_and_wait(env_t env) 391{ 392 return test_ipc_pair(env, call_func, reply_and_wait_func, false, env->cores); 393} 394DEFINE_TEST(IPC0003, "Test SMP seL4_Send + seL4_Reply + seL4_Recv", test_call_reply_and_wait, true) 395 396static int 397test_nbsend_wait(env_t env) 398{ 399 return test_ipc_pair(env, nbsend_func, nbwait_func, false, 1); 400} 401DEFINE_TEST(IPC0004, "Test seL4_NBSend + seL4_Recv", test_nbsend_wait, true) 402 403static int 404test_send_wait_interas(env_t env) 405{ 406 return test_ipc_pair(env, send_func, wait_func, true, env->cores); 407} 408DEFINE_TEST(IPC1001, "Test SMP inter-AS seL4_Send + seL4_Recv", test_send_wait_interas, true) 409 410static int 411test_call_replywait_interas(env_t env) 412{ 413 return test_ipc_pair(env, call_func, replywait_func, true, env->cores); 414} 415DEFINE_TEST(IPC1002, "Test SMP inter-AS seL4_Call + seL4_ReplyRecv", test_call_replywait_interas, true) 416 417static int 418test_call_reply_and_wait_interas(env_t env) 419{ 420 return test_ipc_pair(env, call_func, reply_and_wait_func, true, env->cores); 421} 422DEFINE_TEST(IPC1003, "Test SMP inter-AS seL4_Send + seL4_Reply + seL4_Recv", test_call_reply_and_wait_interas, true) 423 424static int 425test_nbsend_wait_interas(env_t env) 426{ 427 return test_ipc_pair(env, nbsend_func, nbwait_func, true, 1); 428} 429DEFINE_TEST(IPC1004, "Test inter-AS seL4_NBSend + seL4_Recv", test_nbsend_wait_interas, true) 430 431static int 432test_ipc_abort_in_call(env_t env) 433{ 434 helper_thread_t thread_a; 435 vka_t *vka = &env->vka; 436 437 seL4_CPtr ep = vka_alloc_endpoint_leaky(vka); 438 seL4_CPtr reply = vka_alloc_reply_leaky(vka); 439 440 seL4_Word start_number = 0xabbacafe; 441 442 create_helper_thread(env, &thread_a); 443 set_helper_priority(env, &thread_a, 100); 444 445 start_helper(env, &thread_a, (helper_fn_t) call_func, ep, start_number, 0, 0); 446 447 /* Wait for the endpoint that it's going to call. */ 448 seL4_Word sender_badge = 0; 449 450 api_recv(ep, &sender_badge, reply); 451 452 /* Now suspend the thread. */ 453 seL4_TCB_Suspend(get_helper_tcb(&thread_a)); 454 455 /* Now resume the thread. */ 456 seL4_TCB_Resume(get_helper_tcb(&thread_a)); 457 458 /* Now suspend it again for good measure. */ 459 seL4_TCB_Suspend(get_helper_tcb(&thread_a)); 460 461 /* And delete it. */ 462 cleanup_helper(env, &thread_a); 463 464 return sel4test_get_result(); 465} 466DEFINE_TEST(IPC0010, "Test suspending an IPC mid-Call()", test_ipc_abort_in_call, true) 467 468#ifdef CONFIG_KERNEL_MCS 469#define RUNS 10 470static void 471server_fn(seL4_CPtr endpoint, seL4_CPtr reply, volatile int *state) 472{ 473 /* signal the intialiser that we are done */ 474 ZF_LOGD("Server call"); 475 *state = *state + 1; 476 seL4_MessageInfo_t info = api_nbsend_recv(endpoint, info, endpoint, NULL, reply); 477 /* from here on we are running on borrowed time */ 478 ZF_LOGD("Server awake!\n"); 479 int i = 0; 480 while (i < RUNS) { 481 test_eq(seL4_GetMR(0), (seL4_Word) 12345678); 482 seL4_SetMR(0, 0xdeadbeef); 483 *state = *state + 1; 484 ZF_LOGD("Server replyRecv\n"); 485 info = seL4_ReplyRecv(endpoint, info, NULL, reply); 486 i++; 487 } 488} 489 490static void proxy_fn(seL4_CPtr receive_endpoint, seL4_CPtr call_endpoint, seL4_Word reply, volatile int *state) 491{ 492 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 493 494 /* signal the initialiser that we are awake */ 495 ZF_LOGD("Proxy nbsendrecv, sending on ep %lu, receiving on ep %lu, reply is %lu\n", call_endpoint, receive_endpoint, 496 reply); 497 *state = *state + 1; 498 info = api_nbsend_recv(call_endpoint, info, receive_endpoint, NULL, reply); 499 /* when we get here we are running on a donated scheduling context, 500 as the initialiser has taken ours away */ 501 502 int i = 0; 503 while (i < RUNS) { 504 test_eq(seL4_GetMR(0), (seL4_Word) 12345678); 505 seL4_SetMR(0, 12345678); 506 507 ZF_LOGD("Proxy call\n"); 508 seL4_Call(call_endpoint, info); 509 510 test_eq(seL4_GetMR(0), (seL4_Word) 0xdeadbeef); 511 512 seL4_SetMR(0, 0xdeadbeef); 513 ZF_LOGD("Proxy replyRecv\n"); 514 *state = *state + 1; 515 info = seL4_ReplyRecv(receive_endpoint, info, NULL, reply); 516 i++; 517 } 518} 519 520static void client_fn(seL4_CPtr endpoint, bool fastpath, int unused, volatile int *state) 521{ 522 523 /* make the message greater than 4 in size if we do not want to hit the fastpath */ 524 uint32_t length = fastpath ? 1 : 8; 525 526 int i = 0; 527 while (i < RUNS) { 528 seL4_SetMR(0, 12345678); 529 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, length); 530 531 ZF_LOGD("Client calling on ep %lu\n", endpoint); 532 info = seL4_Call(endpoint, info); 533 534 test_eq(seL4_GetMR(0), (seL4_Word) 0xdeadbeef); 535 i++; 536 *state = *state + 1; 537 } 538} 539 540static int single_client_server_chain_test(env_t env, int fastpath, int prio_diff) 541{ 542 const int num_proxies = 5; 543 int client_prio = 10; 544 int server_prio = client_prio + (prio_diff * num_proxies); 545 helper_thread_t client, server; 546 helper_thread_t proxies[num_proxies]; 547 volatile int client_state = 0; 548 volatile int server_state = 0; 549 volatile int proxy_state[num_proxies]; 550 551 create_helper_thread(env, &client); 552 set_helper_priority(env, &client, client_prio); 553 554 seL4_CPtr receive_endpoint = vka_alloc_endpoint_leaky(&env->vka); 555 seL4_CPtr first_endpoint = receive_endpoint; 556 557 /* create proxies */ 558 for (int i = 0; i < num_proxies; i++) { 559 int prio = server_prio + (prio_diff * i); 560 proxy_state[i] = 0; 561 seL4_CPtr call_endpoint = vka_alloc_endpoint_leaky(&env->vka); 562 create_helper_thread(env, &proxies[i]); 563 set_helper_priority(env, &proxies[i], prio); 564 ZF_LOGD("Start proxy\n"); 565 start_helper(env, &proxies[i], (helper_fn_t) proxy_fn, receive_endpoint, 566 call_endpoint, proxies[i].thread.reply.cptr, (seL4_Word) &proxy_state[i]); 567 568 /* wait for proxy to initialise */ 569 ZF_LOGD("Recv for proxy\n"); 570 seL4_Wait(call_endpoint, NULL); 571 test_eq(proxy_state[i], 1); 572 /* now take away its scheduling context */ 573 int error = api_sc_unbind(proxies[i].thread.sched_context.cptr); 574 test_eq(error, seL4_NoError); 575 receive_endpoint = call_endpoint; 576 } 577 578 /* create the server */ 579 create_helper_thread(env, &server); 580 set_helper_priority(env, &server, server_prio); 581 ZF_LOGD("Start server"); 582 start_helper(env, &server, (helper_fn_t) server_fn, receive_endpoint, server.thread.reply.cptr, 583 (seL4_Word) &server_state, 0); 584 /* wait for server to initialise on our time */ 585 ZF_LOGD("Recv for server"); 586 seL4_Wait(receive_endpoint, NULL); 587 test_eq(server_state, 1); 588 589 /* now take it's scheduling context away */ 590 int error = api_sc_unbind(server.thread.sched_context.cptr); 591 test_eq(error, seL4_NoError); 592 593 ZF_LOGD("Start client"); 594 start_helper(env, &client, (helper_fn_t) client_fn, first_endpoint, 595 fastpath, RUNS, (seL4_Word) &client_state); 596 597 /* sleep and let the testrun */ 598 ZF_LOGD("wait_for_helper() for client"); 599 wait_for_helper(&client); 600 601 test_eq(server_state, RUNS + 1); 602 test_eq(client_state, RUNS); 603 for (int i = 0; i < num_proxies; i++) { 604 test_eq(proxy_state[i], RUNS + 1); 605 } 606 607 return sel4test_get_result(); 608} 609 610int test_single_client_slowpath_same_prio(env_t env) 611{ 612 return single_client_server_chain_test(env, 0, 0); 613} 614DEFINE_TEST(IPC0011, "Client-server inheritance: slowpath, same prio", test_single_client_slowpath_same_prio, 615 config_set(CONFIG_KERNEL_MCS)) 616 617int test_single_client_slowpath_higher_prio(env_t env) 618{ 619 return single_client_server_chain_test(env, 0, 1); 620} 621DEFINE_TEST(IPC0012, "Client-server inheritance: slowpath, client higher prio", 622 test_single_client_slowpath_higher_prio, config_set(CONFIG_KERNEL_MCS)) 623 624int test_single_client_slowpath_lower_prio(env_t env) 625{ 626 return single_client_server_chain_test(env, 0, -1); 627} 628DEFINE_TEST(IPC0013, "Client-server inheritance: slowpath, client lower prio", 629 test_single_client_slowpath_lower_prio, config_set(CONFIG_KERNEL_MCS)) 630 631int test_single_client_fastpath_higher_prio(env_t env) 632{ 633 return single_client_server_chain_test(env, 1, 1); 634} 635DEFINE_TEST(IPC0014, "Client-server inheritance: fastpath, client higher prio", test_single_client_fastpath_higher_prio, 636 config_set(CONFIG_KERNEL_MCS)) 637 638int 639test_single_client_fastpath_same_prio(env_t env) 640{ 641 return single_client_server_chain_test(env, 1, 0); 642} 643DEFINE_TEST(IPC0015, "Client-server inheritance: fastpath, client same prio", test_single_client_fastpath_same_prio, 644 config_set(CONFIG_KERNEL_MCS)) 645 646static void 647ipc0016_call_once_fn(seL4_CPtr endpoint, volatile int *state) 648{ 649 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 650 *state = *state + 1; 651 ZF_LOGD("Call %d\n", *state); 652 seL4_Call(endpoint, info); 653 ZF_LOGD("Resumed with reply\n"); 654 *state = *state + 1; 655} 656 657static void ipc0016_reply_once_fn(seL4_CPtr endpoint, seL4_CPtr reply) 658{ 659 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 660 661 /* send initialisation context back */ 662 ZF_LOGD("seL4_nbsendrecv\n"); 663 api_nbsend_recv(endpoint, info, endpoint, NULL, reply); 664 665 /* reply */ 666 ZF_LOGD("Reply\n"); 667 seL4_Send(reply, info); 668 669 /* wait (keeping sc) */ 670 ZF_LOGD("Recv\n"); 671 seL4_Wait(endpoint, NULL); 672 673 test_check(!"should not get here"); 674} 675 676static int test_transfer_on_reply(env_t env) 677{ 678 volatile int state = 1; 679 helper_thread_t client, server; 680 681 seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka); 682 create_helper_thread(env, &client); 683 create_helper_thread(env, &server); 684 685 set_helper_priority(env, &client, 10); 686 set_helper_priority(env, &server, 11); 687 688 start_helper(env, &server, (helper_fn_t) ipc0016_reply_once_fn, endpoint, server.thread.reply.cptr, 0, 0); 689 690 /* wait for server to initialise */ 691 seL4_Wait(endpoint, NULL); 692 /* now remove the schedluing context */ 693 int error = api_sc_unbind(server.thread.sched_context.cptr); 694 test_eq(error, seL4_NoError); 695 696 /* start the client */ 697 start_helper(env, &client, (helper_fn_t) ipc0016_call_once_fn, endpoint, 698 (seL4_Word) &state, 0, 0); 699 /* the server will attempt to steal the clients scheduling context 700 * by using seL4_Send instead of seL4_ReplyWait. However, 701 * a reply cap is a guarantee that a scheduling context will be returned, 702 * so it does return to the client and the server hangs. 703 */ 704 wait_for_helper(&client); 705 706 test_eq(state, 3); 707 708 return sel4test_get_result(); 709} 710DEFINE_TEST(IPC0016, "Test reply returns scheduling context", 711 test_transfer_on_reply, config_set(CONFIG_KERNEL_MCS)); 712 713/* used by ipc0017 and ipc0019 */ 714static void sender(seL4_CPtr endpoint, volatile int *state) 715{ 716 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 717 ZF_LOGD("Client send\n"); 718 *state = 1; 719 seL4_Send(endpoint, info); 720 *state = 2; 721} 722 723static void wait_server(seL4_CPtr endpoint, int messages) 724{ 725 /* signal test that we are initialised */ 726 seL4_Send(endpoint, seL4_MessageInfo_new(0, 0, 0, 0)); 727 int i = 0; 728 while (i < messages) { 729 ZF_LOGD("Server wait\n"); 730 seL4_Wait(endpoint, NULL); 731 i++; 732 } 733} 734 735static int test_send_to_no_sc(env_t env) 736{ 737 /* sends should block until the server gets a scheduling context. 738 * nb sends should not block */ 739 helper_thread_t server, client1, client2; 740 741 seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka); 742 743 create_helper_thread(env, &server); 744 create_helper_thread(env, &client1); 745 create_helper_thread(env, &client2); 746 747 set_helper_priority(env, &server, 10); 748 set_helper_priority(env, &client1, 9); 749 set_helper_priority(env, &client2, 9); 750 751 const int num_server_messages = 4; 752 start_helper(env, &server, (helper_fn_t) wait_server, endpoint, num_server_messages, 0, 0); 753 seL4_Wait(endpoint, NULL); 754 755 int error = api_sc_unbind(server.thread.sched_context.cptr); 756 test_eq(error, seL4_NoError); 757 758 /* this message should not result in the server being scheduled */ 759 ZF_LOGD("NBSend"); 760 seL4_SetMR(0, 12345678); 761 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 1); 762 seL4_NBSend(endpoint, info); 763 test_eq(seL4_GetMR(0), (seL4_Word)12345678); 764 765 /* start clients */ 766 volatile int state1 = 0; 767 volatile int state2 = 0; 768 start_helper(env, &client1, (helper_fn_t) sender, endpoint, (seL4_Word) &state1, 0, 0); 769 start_helper(env, &client2, (helper_fn_t) sender, endpoint, (seL4_Word) &state2, 0, 0); 770 771 /* set our prio down, both clients should block as the server cannot 772 * run without a schedluing context */ 773 error = seL4_TCB_SetPriority(env->tcb, env->tcb, 8); 774 test_eq(error, seL4_NoError); 775 test_eq(state1, 1); 776 test_eq(state2, 1); 777 778 /* restore the servers schedluing context */ 779 error = api_sc_bind(server.thread.sched_context.cptr, server.thread.tcb.cptr); 780 test_eq(error, seL4_NoError); 781 782 /* now the clients should be unblocked */ 783 test_eq(state1, 2); 784 test_eq(state2, 2); 785 786 /* this should work */ 787 seL4_NBSend(endpoint, info); 788 789 /* and so should this */ 790 seL4_Send(endpoint, info); 791 792 /* if the server received the correct number of messages it should now be done */ 793 wait_for_helper(&server); 794 795 return sel4test_get_result(); 796} 797DEFINE_TEST(IPC0017, "Test seL4_Send/seL4_NBSend to a server with no scheduling context", test_send_to_no_sc, 798 config_set(CONFIG_KERNEL_MCS)) 799 800static void 801ipc0018_helper(seL4_CPtr endpoint, volatile int *state) 802{ 803 *state = 1; 804 805 while (1) { 806 ZF_LOGD("Send"); 807 seL4_Send(endpoint, seL4_MessageInfo_new(0, 0, 0, 0)); 808 *state = *state + 1; 809 } 810} 811 812static int test_receive_no_sc(env_t env) 813{ 814 helper_thread_t client; 815 volatile int state = 0; 816 seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka); 817 create_helper_thread(env, &client); 818 set_helper_priority(env, &client, 10); 819 int error = seL4_TCB_SetPriority(env->tcb, env->tcb, 9); 820 test_eq(error, seL4_NoError); 821 822 /* start the client, it will increment state and send a message */ 823 start_helper(env, &client, (helper_fn_t) ipc0018_helper, endpoint, 824 (seL4_Word) &state, 0, 0); 825 826 test_eq(state, 1); 827 828 /* clear the clients scheduling context */ 829 ZF_LOGD("Unbind scheduling context"); 830 error = api_sc_unbind(client.thread.sched_context.cptr); 831 test_eq(error, seL4_NoError); 832 833 /* now we should be able to receive the message, but since the client 834 * no longer has a schedluing context it should not run 835 */ 836 ZF_LOGD("Recv"); 837 seL4_Wait(endpoint, NULL); 838 839 /* check thread has not run */ 840 test_eq(state, 1); 841 842 /* now set the schedluing context again */ 843 error = api_sc_bind(client.thread.sched_context.cptr, 844 client.thread.tcb.cptr); 845 test_eq(error, seL4_NoError); 846 test_eq(state, 2); 847 848 /* now get another message */ 849 seL4_Wait(endpoint, NULL); 850 test_eq(state, 3); 851 852 /* and another, to check client is well and truly running */ 853 seL4_Wait(endpoint, NULL); 854 test_eq(state, 4); 855 856 return sel4test_get_result(); 857} 858DEFINE_TEST(IPC0018, "Test receive from a client with no scheduling context", 859 test_receive_no_sc, config_set(CONFIG_KERNEL_MCS)); 860 861static int delete_sc_client_sending_on_endpoint(env_t env) 862{ 863 helper_thread_t client; 864 volatile int state = 0; 865 866 seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka); 867 868 create_helper_thread(env, &client); 869 set_helper_priority(env, &client, 10); 870 871 /* set our prio below the helper */ 872 int error = seL4_TCB_SetPriority(env->tcb, env->tcb, 9); 873 test_eq(error, seL4_NoError); 874 875 start_helper(env, &client, (helper_fn_t) sender, endpoint, (seL4_Word) &state, 0, 0); 876 877 /* the client will run and send on the endpoint */ 878 test_eq(state, 1); 879 880 /* now delete the scheduling context - this should unbind the client 881 * but not remove the message */ 882 883 ZF_LOGD("Destroying schedluing context"); 884 vka_free_object(&env->vka, &client.thread.sched_context); 885 886 ZF_LOGD("seL4_Wait"); 887 seL4_Wait(endpoint, NULL); 888 test_eq(state, 1); 889 890 return sel4test_get_result(); 891} 892DEFINE_TEST(IPC0019, "Test deleteing the scheduling context while a client is sending on an endpoint", 893 delete_sc_client_sending_on_endpoint, config_set(CONFIG_KERNEL_MCS)); 894 895static void ipc0020_helper(seL4_CPtr endpoint, volatile int *state) 896{ 897 *state = 1; 898 while (1) { 899 ZF_LOGD("Recv"); 900 seL4_Wait(endpoint, NULL); 901 *state = *state + 1; 902 } 903} 904 905static int delete_sc_client_waiting_on_endpoint(env_t env) 906{ 907 helper_thread_t waiter; 908 volatile int state = 0; 909 seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka); 910 911 create_helper_thread(env, &waiter); 912 set_helper_priority(env, &waiter, 10); 913 int error = seL4_TCB_SetPriority(env->tcb, env->tcb, 9); 914 start_helper(env, &waiter, (helper_fn_t) ipc0020_helper, endpoint, (seL4_Word) &state, 0, 0); 915 916 /* helper should run and block receiving on endpoint */ 917 test_eq(state, 1); 918 919 /* destroy scheduling context */ 920 vka_free_object(&env->vka, &waiter.thread.sched_context); 921 922 /* send message */ 923 seL4_Send(endpoint, seL4_MessageInfo_new(0, 0, 0, 0)); 924 925 /* thread should not have moved */ 926 test_eq(state, 1); 927 928 /* now create a new scheduling context and give it to the thread */ 929 seL4_CPtr sched_context = vka_alloc_sched_context_leaky(&env->vka); 930 error = api_sched_ctrl_configure(simple_get_sched_ctrl(&env->simple, 0), sched_context, 931 1000 * US_IN_S, 1000 * US_IN_S, 0, 0); 932 test_eq(error, seL4_NoError); 933 934 error = api_sc_bind(sched_context, waiter.thread.tcb.cptr); 935 test_eq(error, seL4_NoError); 936 937 /* now the thread should run and receive the message */ 938 test_eq(state, 2); 939 940 return sel4test_get_result(); 941} 942DEFINE_TEST(IPC0020, "test deleting a scheduling context while the client is waiting on an endpoint", 943 delete_sc_client_waiting_on_endpoint, config_set(CONFIG_KERNEL_MCS)); 944 945static void ipc21_faulter_fn(int *addr) 946{ 947 ZF_LOGD("Fault at %p\n", addr); 948 *addr = 0xdeadbeef; 949 ZF_LOGD("Resumed\n"); 950} 951 952static void ipc21_fault_handler_fn(seL4_CPtr endpoint, vspace_t *vspace, reservation_t *res, seL4_CPtr reply) 953{ 954 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 955 info = api_nbsend_recv(endpoint, info, endpoint, NULL, reply); 956 957 while (1) { 958 test_check(seL4_isVMFault_tag(info)); 959 void *addr = (void *) seL4_GetMR(seL4_VMFault_Addr); 960 ZF_LOGD("Handling fault at %p\n", addr); 961 int error = vspace_new_pages_at_vaddr(vspace, addr, 1, seL4_PageBits, *res); 962 test_eq(error, seL4_NoError); 963 seL4_ReplyRecv(endpoint, info, NULL, reply); 964 } 965} 966 967static int test_fault_handler_donated_sc(env_t env) 968{ 969 helper_thread_t handler, faulter; 970 void *vaddr = NULL; 971 972 seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka); 973 reservation_t res = vspace_reserve_range(&env->vspace, PAGE_SIZE_4K, seL4_AllRights, 1, &vaddr); 974 test_check(vaddr != NULL); 975 976 create_helper_thread(env, &handler); 977 create_helper_thread(env, &faulter); 978 979 /* start fault handler */ 980 start_helper(env, &handler, (helper_fn_t) ipc21_fault_handler_fn, 981 endpoint, (seL4_Word) &env->vspace, (seL4_Word) &res, 982 handler.thread.reply.cptr); 983 984 /* wait for it to initialise */ 985 seL4_Wait(endpoint, NULL); 986 987 /* now remove its scheduling context */ 988 int error = api_sc_unbind(handler.thread.sched_context.cptr); 989 test_eq(error, seL4_NoError); 990 991 /* set fault handler */ 992 seL4_Word data = api_make_guard_skip_word(seL4_WordBits - env->cspace_size_bits); 993 error = api_tcb_set_space(faulter.thread.tcb.cptr, endpoint, 994 env->cspace_root, data, env->page_directory, seL4_NilData); 995 test_eq(error, seL4_NoError); 996 997 /* start the fault handler */ 998 start_helper(env, &faulter, (helper_fn_t) ipc21_faulter_fn, (seL4_Word) vaddr, 0, 0, 0); 999 /* the faulter handler will restore the faulter and we should not block here */ 1000 wait_for_helper(&faulter); 1001 1002 return sel4test_get_result(); 1003} 1004DEFINE_TEST(IPC0021, "Test fault handler on donated scheduling context", 1005 test_fault_handler_donated_sc, config_set(CONFIG_KERNEL_MCS)); 1006 1007static void ipc22_client_fn(seL4_CPtr endpoint, volatile int *state) 1008{ 1009 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 1010 ZF_LOGD("Client init"); 1011 seL4_Call(endpoint, info); 1012 *state = *state + 1; 1013 ZF_LOGD("Client receive reply"); 1014} 1015 1016static seL4_CPtr ipc22_go; 1017 1018static void ipc22_server_fn(seL4_CPtr init_ep, seL4_CPtr reply_cap) 1019{ 1020 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 1021 ZF_LOGD("Server init\n"); 1022 1023 /* wait for the signal to go from the test runner - 1024 * we have to block here to wait for all the clients to 1025 * start and queue up - otherwise they will all be served 1026 * by the same server and the point is to test stack spawning */ 1027 api_nbsend_wait(init_ep, info, init_ep, NULL); 1028 1029 ZF_LOGD("Server reply to fwded cap\n"); 1030 seL4_Send(reply_cap, info); 1031} 1032 1033static void ipc22_stack_spawner_fn(env_t env, seL4_CPtr endpoint, int server_prio, seL4_Word unused) 1034{ 1035 helper_thread_t servers[RUNS]; 1036 seL4_CPtr init_ep = vka_alloc_endpoint_leaky(&env->vka); 1037 1038 /* first we signal to endpoint to tell the test runner we are ready */ 1039 seL4_CPtr first_ep = endpoint; 1040 ZF_LOGD("Stack spawner init"); 1041 1042 for (int i = 0; i < RUNS; i++) { 1043 create_helper_thread(env, &servers[i]); 1044 set_helper_priority(env, &servers[i], server_prio); 1045 1046 api_nbsend_recv(first_ep, seL4_MessageInfo_new(0, 0, 0, 0), endpoint, NULL, 1047 servers[i].thread.reply.cptr); 1048 1049 /* after the first nbsend, we want to signal the clients via init_ep */ 1050 first_ep = init_ep; 1051 1052 ZF_LOGD("Got another client\n"); 1053 /* start helper and allow to initialise */ 1054 ZF_LOGD("Spawn server\n"); 1055 start_helper(env, &servers[i], (helper_fn_t) ipc22_server_fn, init_ep, 1056 servers[i].thread.reply.cptr, 0, 0); 1057 /* wait for it to block */ 1058 seL4_Wait(init_ep, NULL); 1059 1060 /* now remove the schedling context */ 1061 int error = api_sc_unbind(servers[i].thread.sched_context.cptr); 1062 test_eq(error, seL4_NoError); 1063 } 1064 1065 /* signal the last client */ 1066 api_nbsend_wait(first_ep, seL4_MessageInfo_new(0, 0, 0, 0), endpoint, NULL); 1067} 1068 1069static int test_stack_spawning_server(env_t env) 1070{ 1071 helper_thread_t clients[RUNS]; 1072 helper_thread_t stack_spawner; 1073 seL4_CPtr endpoint = vka_alloc_endpoint_leaky(&env->vka); 1074 ipc22_go = vka_alloc_endpoint_leaky(&env->vka); 1075 volatile int state = 0; 1076 int our_prio = 10; 1077 1078 create_helper_thread(env, &stack_spawner); 1079 set_helper_mcp(env, &stack_spawner, seL4_MaxPrio); 1080 start_helper(env, &stack_spawner, (helper_fn_t) ipc22_stack_spawner_fn, 1081 (seL4_Word) env, endpoint, our_prio + 1, RUNS); 1082 1083 /* wait for stack spawner to init */ 1084 ZF_LOGD("Wait for stack spawner to init"); 1085 seL4_Wait(endpoint, NULL); 1086 1087 /* take away scheduling context */ 1088 int error = api_sc_unbind(stack_spawner.thread.sched_context.cptr); 1089 test_eq(error, seL4_NoError); 1090 1091 set_helper_priority(env, &stack_spawner, our_prio + 2); 1092 1093 error = seL4_TCB_SetPriority(env->tcb, env->tcb, our_prio); 1094 test_eq(error, seL4_NoError); 1095 1096 set_helper_priority(env, &stack_spawner, our_prio + 2); 1097 set_helper_mcp(env, &stack_spawner, seL4_MaxPrio - 1); 1098 1099 ZF_LOGD("Starting clients"); 1100 /* create and start clients */ 1101 for (int i = 0; i < RUNS; i++) { 1102 create_helper_thread(env, &clients[i]); 1103 set_helper_priority(env, &clients[i], our_prio + 1); 1104 start_helper(env, &clients[i], (helper_fn_t) ipc22_client_fn, endpoint, (seL4_Word) &state, i, 0); 1105 } 1106 1107 /* set our priority down so servers can run */ 1108 error = seL4_TCB_SetPriority(env->tcb, env->tcb, our_prio - 2); 1109 test_eq(error, seL4_NoError); 1110 1111 for (int i = 0; i < RUNS; i++) { 1112 wait_for_helper(&clients[i]); 1113 } 1114 1115 ZF_LOGD("Done"); 1116 1117 /* make sure all the clients got served */ 1118 test_eq(state, RUNS); 1119 1120 return sel4test_get_result(); 1121} 1122DEFINE_TEST(IPC0022, "Test stack spawning server with scheduling context donation", 1123 test_stack_spawning_server, config_set(CONFIG_KERNEL_MCS)); 1124 1125static void ipc23_client_fn(seL4_CPtr ep, volatile int *state) 1126{ 1127 seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 0); 1128 1129 *state = 1; 1130 1131 ZF_LOGD("Call"); 1132 seL4_Call(ep, info); 1133 /* should not get here */ 1134 *state = 2; 1135} 1136 1137/* used by ipc0023 and 0024 */ 1138static void ipc23_server_fn(seL4_CPtr client_ep, seL4_CPtr wait_ep, seL4_CPtr reply) 1139{ 1140 /* send to the wait_ep to tell the test we are initialised, 1141 * then wait on the client_ep to receive a scheduling context */ 1142 api_nbsend_recv(wait_ep, seL4_MessageInfo_new(0, 0, 0, 0), client_ep, NULL, reply); 1143 1144 /* now block */ 1145 seL4_Wait(wait_ep, NULL); 1146} 1147 1148static int test_delete_reply_cap_sc(env_t env) 1149{ 1150 helper_thread_t client, server; 1151 volatile int state = 0; 1152 seL4_CPtr client_ep = vka_alloc_endpoint_leaky(&env->vka); 1153 seL4_CPtr server_ep = vka_alloc_endpoint_leaky(&env->vka); 1154 1155 create_helper_thread(env, &client); 1156 create_helper_thread(env, &server); 1157 1158 start_helper(env, &client, (helper_fn_t) ipc23_client_fn, client_ep, 1159 (seL4_Word) &state, 0, 0); 1160 start_helper(env, &server, (helper_fn_t) ipc23_server_fn, client_ep, 1161 server_ep, server.thread.reply.cptr, 0); 1162 1163 /* wait for server to init */ 1164 seL4_Wait(server_ep, NULL); 1165 /* take its scheduling context away */ 1166 int error = api_sc_unbind(server.thread.sched_context.cptr); 1167 test_eq(error, seL4_NoError); 1168 1169 /* set the client and server prio higher than ours so they can run */ 1170 error = seL4_TCB_SetPriority(env->tcb, env->tcb, 10); 1171 test_eq(error, seL4_NoError); 1172 1173 set_helper_priority(env, &client, 11); 1174 set_helper_priority(env, &server, 11); 1175 1176 /* now the client should have run and called the server*/ 1177 test_eq(state, 1); 1178 1179 /* delete scheduling context */ 1180 vka_free_object(&env->vka, & client.thread.sched_context); 1181 1182 /* try to reply, the client should not run as it has no scheduling context */ 1183 seL4_Signal(server.thread.reply.cptr); 1184 test_eq(state, 1); 1185 1186 return sel4test_get_result(); 1187} 1188DEFINE_TEST(IPC0023, "Test deleting the scheduling context tracked in a reply cap", 1189 test_delete_reply_cap_sc, config_set(CONFIG_KERNEL_MCS)) 1190 1191static int test_delete_reply_cap_then_sc(env_t env) 1192{ 1193 helper_thread_t client, server; 1194 volatile int state = 0; 1195 1196 seL4_CPtr client_ep = vka_alloc_endpoint_leaky(&env->vka); 1197 seL4_CPtr server_ep = vka_alloc_endpoint_leaky(&env->vka); 1198 1199 create_helper_thread(env, &client); 1200 create_helper_thread(env, &server); 1201 1202 set_helper_priority(env, &client, 11); 1203 set_helper_priority(env, &server, 11); 1204 /* start server */ 1205 start_helper(env, &server, (helper_fn_t) ipc23_server_fn, client_ep, 1206 server_ep, server.thread.reply.cptr, 0); 1207 1208 ZF_LOGD("Waiting for server"); 1209 /* wait for server to init */ 1210 seL4_Wait(server_ep, NULL); 1211 1212 /* set our prio down so client can run */ 1213 int error = seL4_TCB_SetPriority(env->tcb, env->tcb, 10); 1214 test_eq(error, 0); 1215 1216 ZF_LOGD("Removed sc\n"); 1217 /* remove schedluing context */ 1218 error = api_sc_unbind(server.thread.sched_context.cptr); 1219 test_eq(error, seL4_NoError); 1220 1221 ZF_LOGD("Start client"); 1222 /* start client */ 1223 start_helper(env, &client, (helper_fn_t) ipc23_client_fn, client_ep, 1224 (seL4_Word) &state, 0, 0); 1225 /* client should have started */ 1226 test_eq(state, 1); 1227 1228 ZF_LOGD("Steal reply cap "); 1229 /* nuke the reply cap */ 1230 vka_free_object(&env->vka, &server.thread.reply); 1231 /* nuke the sc */ 1232 vka_free_object(&env->vka, &client.thread.sched_context); 1233 1234 ZF_LOGD("Done"); 1235 /* caller should not run */ 1236 test_eq(1, state); 1237 1238 return sel4test_get_result(); 1239} 1240DEFINE_TEST(IPC0024, "Test deleting the reply cap in the scheduling context", 1241 test_delete_reply_cap_then_sc, config_set(CONFIG_KERNEL_MCS)); 1242 1243static int test_nbsendrecv(env_t env) 1244{ 1245 return test_ipc_pair(env, (test_func_t) nbsendrecv_func, (test_func_t) nbsendrecv_func, false, env->cores); 1246} 1247DEFINE_TEST(IPC0025, "Test seL4_nbsendrecv + seL4_nbsendrecv", test_nbsendrecv, config_set(CONFIG_KERNEL_MCS)) 1248 1249static int test_nbsendrecv_interas(env_t env) 1250{ 1251 return test_ipc_pair(env, (test_func_t) nbsendrecv_func, (test_func_t) nbsendrecv_func, false, env->cores); 1252} 1253DEFINE_TEST(IPC0026, "Test interas seL4_nbsendrecv + seL4_nbsendrecv", test_nbsendrecv_interas, 1254 config_set(CONFIG_KERNEL_MCS)) 1255 1256static int 1257test_sched_donation_low_prio_server(env_t env) 1258{ 1259 helper_thread_t client, server, server2; 1260 seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka); 1261 1262 create_helper_thread(env, &client); 1263 create_helper_thread(env, &server); 1264 create_helper_thread(env, &server2); 1265 1266 int error = create_passive_thread(env, &server, (helper_fn_t) replywait_func, ep, 0, server.thread.reply.cptr, 0); 1267 test_eq(error, seL4_NoError); 1268 1269 /* make client higher prio than server */ 1270 set_helper_priority(env, &server, 1); 1271 set_helper_priority(env, &client, 2); 1272 1273 ZF_LOGD("Start client"); 1274 start_helper(env, &client, (helper_fn_t) call_func, ep, 0, 0, 0); 1275 1276 ZF_LOGD("Wait for helper"); 1277 wait_for_helper(&client); 1278 1279 /* give server a sc to finish on */ 1280 error = api_sc_bind(server.thread.sched_context.cptr, 1281 server.thread.tcb.cptr); 1282 test_eq(error, 0); 1283 wait_for_helper(&server); 1284 1285 /* now try again, but start the client first */ 1286 start_helper(env, &client, (helper_fn_t) call_func, ep, 0, 0, 0); 1287 error = create_passive_thread(env, &server2, (helper_fn_t) replywait_func, ep, 0, 1288 server2.thread.reply.cptr, 0); 1289 1290 test_eq(error, seL4_NoError); 1291 1292 ZF_LOGD("Wait for helper"); 1293 wait_for_helper(&client); 1294 error = api_sc_bind(server2.thread.sched_context.cptr, 1295 server2.thread.tcb.cptr); 1296 test_eq(error, 0); 1297 wait_for_helper(&server2); 1298 1299 return sel4test_get_result(); 1300} 1301DEFINE_TEST(IPC0027, "Test sched donation to low prio server", test_sched_donation_low_prio_server, 1302 config_set(CONFIG_KERNEL_MCS)) 1303 1304static void 1305ipc28_server_fn(seL4_CPtr ep, seL4_CPtr reply, volatile int *state) 1306{ 1307 api_nbsend_recv(ep, seL4_MessageInfo_new(0, 0, 0, 0), ep, NULL, reply); 1308 while (1) { 1309 *state = *state + 1; 1310 seL4_ReplyRecv(ep, seL4_MessageInfo_new(0, 0, 0, 0), NULL, reply); 1311 } 1312} 1313 1314static int ipc28_client_fn(seL4_CPtr ep, volatile int *state) 1315{ 1316 1317 while (*state < RUNS) { 1318 seL4_Call(ep, seL4_MessageInfo_new(0, 0, 0, 0)); 1319 *state = *state + 1; 1320 } 1321 1322 return 0; 1323} 1324 1325static int test_sched_donation_cross_core(env_t env) 1326{ 1327 seL4_CPtr ep = vka_alloc_endpoint_leaky(&env->vka); 1328 helper_thread_t clients[env->cores - 1]; 1329 helper_thread_t server; 1330 volatile int states[env->cores - 1]; 1331 volatile seL4_Word server_state = 0; 1332 1333 /* start server on core 0 */ 1334 create_helper_thread(env, &server); 1335 1336 /* start a client on each other core */ 1337 for (int i = 0; i < env->cores - 1; i++) { 1338 states[i] = 0; 1339 create_helper_thread(env, &clients[i]); 1340 set_helper_affinity(env, &clients[i], i + 1); 1341 } 1342 1343 /* start server */ 1344 start_helper(env, &server, (helper_fn_t) ipc28_server_fn, ep, get_helper_reply(&server), 1345 (seL4_Word) &server_state, 0); 1346 1347 /* wait for server to init */ 1348 seL4_Wait(ep, NULL); 1349 1350 /* convert to passive */ 1351 int error = api_sc_unbind(get_helper_sched_context(&server)); 1352 test_eq(error, seL4_NoError); 1353 1354 /* start clients */ 1355 for (int i = 0; i < env->cores - 1; i++) { 1356 start_helper(env, &clients[i], (helper_fn_t) ipc28_client_fn, ep, (seL4_Word) &states[i], 0, 0); 1357 } 1358 1359 /* wait for the clients */ 1360 for (int i = 0; i < env->cores - 1; i++) { 1361 error = wait_for_helper(&clients[i]); 1362 test_eq(error, 0); 1363 test_eq(states[i], RUNS); 1364 } 1365 1366 test_eq(server_state, RUNS * (env->cores - 1)); 1367 1368 return sel4test_get_result(); 1369} 1370DEFINE_TEST(IPC0028, "Cross core sched donation", test_sched_donation_cross_core, 1371 config_set(CONFIG_KERNEL_MCS) &&config_set(CONFIG_MAX_NUM_NODES) &&CONFIG_MAX_NUM_NODES > 1); 1372#endif /* CONFIG_KERNEL_MCS */ 1373