static int set_priority_helper_2(seL4_CPtr *t1, seL4_CPtr *t2) { test_check(set_priority_step == 1); ZF_LOGD("1..."); /* Raise thread 1 to equal to ours, which should fail. */ int error = seL4_TCB_SetPriority(*t1, SCHED0005_HIGHEST_PRIO - 1 + PRIORITY_FUDGE); test_check(error == seL4_IllegalOperation); /* Raise thread 1 to just below us. */ error = seL4_TCB_SetPriority(*t1, SCHED0005_HIGHEST_PRIO - 2); test_check(!error); /* Drop ours to below thread 1. Thread 1 should run. */ set_priority_step = 2; error = seL4_TCB_SetPriority(*t2, SCHED0005_HIGHEST_PRIO -3 ); test_check(!error); /* Once thread 1 exits, we should run. */ test_check(set_priority_step == 3); ZF_LOGD("3..."); set_priority_step = 4; return 0; }
/* The enclosed test relies on the current thread being able to create two * threads of unequal priority, both less than the caller's own priority. For * this we need at least 3 priority levels, assuming that the current thread is * running at the highest priority. */ static int test_set_priority(struct env* env) { helper_thread_t thread1; helper_thread_t thread2; ZF_LOGD("test_set_priority starting\n"); create_helper_thread(env, &thread1); set_helper_priority(&thread1, SCHED0005_HIGHEST_PRIO); create_helper_thread(env, &thread2); set_helper_priority(&thread2, SCHED0005_HIGHEST_PRIO - 1); set_priority_step = 0; ZF_LOGD(" "); start_helper(env, &thread1, (helper_fn_t) set_priority_helper_1, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2.thread.tcb.cptr, 0, 0); start_helper(env, &thread2, (helper_fn_t) set_priority_helper_2, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2.thread.tcb.cptr, 0, 0); wait_for_helper(&thread1); wait_for_helper(&thread2); test_check(set_priority_step == 4); ZF_LOGD("\n"); cleanup_helper(env, &thread1); cleanup_helper(env, &thread2); return sel4test_get_result(); }
void run_benchmark(void *faulter_fn, void *handler_fn, seL4_CPtr done_ep) { int error = sel4utils_start_thread(&fault_handler, (sel4utils_thread_entry_fn) handler_fn, (void *) N_HANDLER_ARGS, (void *) handler_argv, true); ZF_LOGF_IF(error, "Failed to start handler"); if (config_set(CONFIG_KERNEL_RT)) { /* convert the fault handler to passive */ ZF_LOGD("Waiting to convert handler to passive"); seL4_Wait(done_ep, NULL); ZF_LOGD("unbound sc\n"); error = api_sc_unbind(fault_handler.sched_context.cptr); ZF_LOGF_IF(error, "Failed to convert to passive"); } error = sel4utils_start_thread(&faulter, (sel4utils_thread_entry_fn) faulter_fn, (void *) N_FAULTER_ARGS, (void *) faulter_argv, true); ZF_LOGF_IF(error, "Failed to start faulter"); /* benchmark runs */ benchmark_wait_children(done_ep, "faulter", 1); if (config_set(CONFIG_KERNEL_RT)) { /* convert the fault handler to active */ ZF_LOGD("Rebound sc\n"); error = api_sc_bind(fault_handler.sched_context.cptr, fault_handler.tcb.cptr); ZF_LOGF_IF(error, "Failed to convert to active"); } benchmark_wait_children(done_ep, "fault handler", 1); error = seL4_TCB_Suspend(faulter.tcb.cptr); ZF_LOGF_IF(error, "Failed to suspend faulter"); error = seL4_TCB_Suspend(fault_handler.tcb.cptr); ZF_LOGF_IF(error, "Failed to suspend fault handler"); }
static int test_suspend(struct env* env) { helper_thread_t thread1; helper_thread_t thread2a; helper_thread_t thread2b; ZF_LOGD("Starting test_suspend\n"); create_helper_thread(env, &thread1); ZF_LOGD("Show me\n"); create_helper_thread(env, &thread2a); create_helper_thread(env, &thread2b); /* First set all the helper threads to have unique priorities * and then start them in order of priority. This is so when * the 'start_helper' function does an IPC to the helper * thread, it doesn't allow one of the already started helper * threads to run at all */ set_helper_priority(&thread1, 0); set_helper_priority(&thread2a, 1); set_helper_priority(&thread2b, 2); start_helper(env, &thread1, (helper_fn_t) suspend_test_helper_1, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2a.thread.tcb.cptr, (seL4_Word) &thread2b.thread.tcb.cptr, 0); start_helper(env, &thread2a, (helper_fn_t) suspend_test_helper_2a, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2a.thread.tcb.cptr, (seL4_Word) &thread2b.thread.tcb.cptr, 0); start_helper(env, &thread2b, (helper_fn_t) suspend_test_helper_2b, (seL4_Word) &thread1.thread.tcb.cptr, (seL4_Word) &thread2a.thread.tcb.cptr, (seL4_Word) &thread2b.thread.tcb.cptr, 0); /* Now set their priorities to what we want */ set_helper_priority(&thread1, 100); set_helper_priority(&thread2a, 101); set_helper_priority(&thread2b, 101); suspend_test_step = 0; ZF_LOGD(" "); wait_for_helper(&thread1); wait_for_helper(&thread2b); CHECK_STEP(suspend_test_step, 6); ZF_LOGD("\n"); cleanup_helper(env, &thread1); cleanup_helper(env, &thread2a); cleanup_helper(env, &thread2b); return sel4test_get_result(); }
int /*? me.interface.name ?*/__run(void) { seL4_Word fault_type; seL4_Word length; seL4_MessageInfo_t info; seL4_Word args[4]; seL4_Word reply_cap = /*? reply_cap_slot ?*/; while (1) { /* Wait for fault */ info = seL4_Recv(/*? ep ?*/, &gdb_state.current_thread_tcb); /* Get the relevant registers */ fault_type = seL4_MessageInfo_get_label(info); length = seL4_MessageInfo_get_length(info); for (int i = 0; i < length; i++) { args[i] = seL4_GetMR(i); } gdb_state.current_pc = args[0]; ZF_LOGD("------------------------------"); ZF_LOGD("Received fault for tcb %zu", gdb_state.current_thread_tcb); ZF_LOGD("Stopped at %zx", gdb_state.current_pc); ZF_LOGD("Length: %zu", length); // Save the reply cap seL4_CNode_SaveCaller(/*? cnode ?*/, reply_cap, 32); gdb_state.stop_reason = find_stop_reason(fault_type, args); gdb_state.current_thread_step_mode = false; /* Send fault message to gdb client */ gdb_handle_fault(&gdb_state); /* Wait for gdb client to deal with fault */ int UNUSED error = b_wait(); /* Reply to the fault ep to restart the thread. We look inside the gdb_state struct to interpret how to restart the thread. */ if (gdb_state.stop_reason == stop_step && gdb_state.current_thread_step_mode==false) { /* If this was a Debug Exception, then we respond with a bp_num and the number of instruction to step Since we're going to continue, we set MR0 to 0 */ info = seL4_MessageInfo_new(0, 0, 0, 1); seL4_SetMR(0, 0); seL4_Send(reply_cap, info); } else if (gdb_state.stop_reason == stop_none) { /* If this was a fault, set the instruction pointer to what we expect it to be */ info = seL4_MessageInfo_new(0, 0, 0, 1); seL4_SetMR(0, gdb_state.current_pc); seL4_Send(reply_cap, info); } else { ZF_LOGD("Responding to some other debug exception %d", gdb_state.stop_reason); seL4_Signal(reply_cap); } } UNREACHABLE(); }
static int test_ipc_prios(struct env* env) { vka_t *vka = &env->vka; helper_thread_t thread0; helper_thread_t thread1; helper_thread_t thread2; helper_thread_t thread3; int result = 0; ipc_test_data_t data; memset(&data, 0, sizeof(data)); data.ep0 = vka_alloc_endpoint_leaky(vka); data.ep1 = vka_alloc_endpoint_leaky(vka); data.ep2 = vka_alloc_endpoint_leaky(vka); data.ep3 = vka_alloc_endpoint_leaky(vka); create_helper_thread(env, &thread0); set_helper_priority(&thread0, 0); create_helper_thread(env, &thread1); set_helper_priority(&thread1, 1); create_helper_thread(env, &thread2); set_helper_priority(&thread2, 2); create_helper_thread(env, &thread3); set_helper_priority(&thread3, 3); data.tcb0 = thread0.thread.tcb.cptr; data.tcb1 = thread1.thread.tcb.cptr; data.tcb2 = thread2.thread.tcb.cptr; data.tcb3 = thread3.thread.tcb.cptr; ZF_LOGD(" "); ipc_test_step = 0; start_helper(env, &thread0, (helper_fn_t) ipc_test_helper_0, (seL4_Word) &data, 0, 0, 0); start_helper(env, &thread1, (helper_fn_t) ipc_test_helper_1, (seL4_Word) &data, 0, 0, 0); start_helper(env, &thread2, (helper_fn_t) ipc_test_helper_2, (seL4_Word) &data, 0, 0, 0); start_helper(env, &thread3, (helper_fn_t) ipc_test_helper_3, (seL4_Word) &data, 0, 0, 0); result |= (int)wait_for_helper(&thread1); result |= (int)wait_for_helper(&thread3); CHECK_STEP(ipc_test_step, 10); ZF_LOGD("\n"); cleanup_helper(env, &thread0); cleanup_helper(env, &thread1); cleanup_helper(env, &thread2); cleanup_helper(env, &thread3); return result; }
/* * Test TCB Resume on self. */ static int test_resume_self(struct env* env) { ZF_LOGD("Starting test_resume_self\n"); /* Ensure nothing bad happens if we resume ourselves. */ int error = seL4_TCB_Resume(env->tcb); test_assert(!error); ZF_LOGD("Ending test_resume_self\n"); return sel4test_get_result(); }
void start_tcpecho() { uint16_t listen_port = short_be(8777); int ret = 0, yes = 1; struct pico_socket *s = NULL; struct pico_ip4 ip4 = {0}; s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpecho); if (!s) { ZF_LOGE("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err)); } pico_socket_setoption(s, PICO_TCP_NODELAY, &yes); ret = pico_socket_bind(s, &ip4, &listen_port); if (ret < 0) { ZF_LOGE("%s: error binding socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err)); } if (pico_socket_listen(s, 40) != 0) { ZF_LOGE("%s: error listening on port %u\n", __FUNCTION__, short_be(listen_port)); } ZF_LOGD("Launching PicoTCP echo server\n"); }
/* * Test that thread suspending works when idling the system. * Note: This test non-deterministically fails. If you find only this test * try re-running the test suite. */ static int test_thread_suspend(env_t env) { helper_thread_t t1; volatile seL4_Word counter; ZF_LOGD("test_thread_suspend\n"); create_helper_thread(env, &t1); set_helper_priority(&t1, 100); start_helper(env, &t1, (helper_fn_t) counter_func, (seL4_Word) &counter, 0, 0, 0); timer_periodic(env->timer->timer, 10 * NS_IN_MS); timer_start(env->timer->timer); sel4_timer_handle_single_irq(env->timer); seL4_Word old_counter; /* Let the counter thread run. We might have a pending interrupt, so * wait twice. */ wait_for_timer_interrupt(env); wait_for_timer_interrupt(env); old_counter = counter; /* Let it run again. */ wait_for_timer_interrupt(env); /* Now, counter should have moved. */ test_check(counter != old_counter); old_counter = counter; /* Suspend the thread, and wait again. */ seL4_TCB_Suspend(t1.thread.tcb.cptr); wait_for_timer_interrupt(env); /* Counter should not have moved. */ test_check(counter == old_counter); old_counter = counter; /* Check once more for good measure. */ wait_for_timer_interrupt(env); /* Counter should not have moved. */ test_check(counter == old_counter); old_counter = counter; /* Resume the thread and check it does move. */ seL4_TCB_Resume(t1.thread.tcb.cptr); wait_for_timer_interrupt(env); test_check(counter != old_counter); /* Done. */ timer_stop(env->timer->timer); sel4_timer_handle_single_irq(env->timer); cleanup_helper(env, &t1); return sel4test_get_result(); }
static int set_priority_helper_1(seL4_CPtr *t1, seL4_CPtr *t2) { test_check(set_priority_step == 0); ZF_LOGD("0..."); set_priority_step = 1; /* * Down our priority. This should force a reschedule and make thread 2 run. */ int error = seL4_TCB_SetPriority(*t1, SCHED0005_HIGHEST_PRIO - 4 ); test_check(!error); test_check(set_priority_step == 2); ZF_LOGD("2..."); set_priority_step = 3; return 0; }
void app_tcpclient() { char *daddr = NULL, *dport = NULL; uint16_t send_port = 0, listen_port = short_be(5555); int i = 0, ret = 0, yes = 1; struct pico_socket *s = NULL; struct pico_ip4 dst = {0}; struct pico_ip4 inaddr = {0}; ZF_LOGD("Connecting to: %s:%d\n", daddr, short_be(send_port)); s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpclient); if (!s) { ZF_LOGE("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err)); } pico_socket_setoption(s, PICO_TCP_NODELAY, &yes); ret = pico_socket_bind(s, &inaddr, &listen_port); if (ret < 0) { ZF_LOGE("%s: error binding socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err)); } // Set the destination address (string) above in the usual xxx.xxx.xxx.xxx ip4 way. pico_string_to_ipv4(daddr, &dst.addr); ret = pico_socket_connect(s, &dst, send_port); if (ret < 0) { ZF_LOGE("%s: error connecting to %s:%u: %s\n", __FUNCTION__, daddr, short_be(send_port), strerror(pico_err)); } ZF_LOGD("TCP client connected\n"); }
static int test_all_priorities(struct env* env) { int i; helper_thread_t **threads = (helper_thread_t **) malloc(sizeof(helper_thread_t*) * NUM_PRIOS); assert(threads != NULL); for (i = 0; i < NUM_PRIOS; i++) { threads[i] = (helper_thread_t*) malloc(sizeof(helper_thread_t)); assert(threads[i]); } vka_t *vka = &env->vka; ZF_LOGD("Testing all thread priorities"); volatile seL4_Word last_prio = MAX_PRIO + 1; seL4_CPtr ep = vka_alloc_endpoint_leaky(vka); for (int prio = MIN_PRIO; prio <= MAX_PRIO; prio++) { int idx = prio - MIN_PRIO; test_check(idx >= 0 && idx < NUM_PRIOS); create_helper_thread(env, threads[idx]); set_helper_priority(threads[idx], prio); start_helper(env, threads[idx], (helper_fn_t) prio_test_func, prio, (seL4_Word) &last_prio, ep, 0); } /* Now block. */ seL4_Word sender_badge = 0; seL4_Recv(ep, &sender_badge); /* When we get woken up, last_prio should be MIN_PRIO. */ test_check(last_prio == MIN_PRIO); for (int prio = MIN_PRIO; prio <= MAX_PRIO; prio++) { int idx = prio - MIN_PRIO; cleanup_helper(env, threads[idx]); free(threads[idx]); } free(threads); return sel4test_get_result(); }
int main(int argc, char *argv[]) { zf_log_set_tag_prefix("hello"); ZF_LOGI("You will see the number of arguments: %i", argc); ZF_LOGD("You will NOT see the first argument: %s", *argv); zf_log_set_output_level(ZF_LOG_WARN); ZF_LOGW("You will see this WARNING message"); ZF_LOGI("You will NOT see this INFO message"); const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " "Aliquam pharetra orci id velit porttitor tempus."; ZF_LOGW_MEM(data, sizeof(data), "Lorem ipsum at %p:", data); return 0; }
static stop_reason_t find_stop_reason(seL4_Word fault_type, seL4_Word *args) { if (fault_type == seL4_Fault_DebugException) { seL4_Word exception_reason = args[1]; ZF_LOGD("MR 0: %zX", args[0]); ZF_LOGD("MR 1: %zX", args[1]); ZF_LOGD("MR 2: %zX", args[2]); ZF_LOGD("MR 3: %zX", args[3]); ZF_LOGD("Breakpoint number %zu", args[1]); if (exception_reason == seL4_DataBreakpoint) { ZF_LOGD("Data breakpoint"); gdb_state.stop_watch_addr = args[2]; return stop_watch; } else if (exception_reason == seL4_InstructionBreakpoint) { ZF_LOGD("Hardware breakpoint"); return stop_hw_break; } else if (exception_reason == seL4_SingleStep && gdb_state.current_thread_step_mode) { return stop_step; } else if (exception_reason == seL4_SoftwareBreakRequest) { ZF_LOGD("Decrementing fault ep because of seL4 kernel behavior"); /* TODO This is a special case where the seL4 kernel gives us a fault instruction pointer that is no the faulting instruction. We decrement the pc to correct for this. In the future the kernel may end up changing the fault ip behavior and this decrement will then need to be removed to account for it. */ gdb_state.current_pc--; delegate_write_register(gdb_state.current_thread_tcb, gdb_state.current_pc, 0); return stop_sw_break; } else { return stop_none; } } else { ZF_LOGE("Unknown fault type: %zd", fault_type); ZF_LOGE("MR 0: %zX", args[0]); ZF_LOGE("MR 1: %zX", args[1]); ZF_LOGE("MR 2: %zX", args[2]); ZF_LOGE("MR 3: %zX", args[3]); return stop_none; } }
/* * TCP code. For TCP, a socket is created and listens. * A callback occurs when the packet is received. The callback handles the different types of TCP events, * including the handshake protocol. * Based off the sample tcpecho app provided in the picotcp library. */ void cb_tcpecho(uint16_t ev, struct pico_socket *s) { int r = 0; ZF_LOGD("tcpecho> wakeup ev=%u\n", ev); if (ev & PICO_SOCK_EV_RD) { char buf[100]; r = pico_socket_read(s, buf, 100); pico_socket_write(s, buf, r); // Immediately echo back a response } if (ev & PICO_SOCK_EV_CONN) { uint32_t ka_val = 0; struct pico_socket *sock_peer; struct pico_ip4 orig = {0}; uint16_t port = 0; char peer[30] = {0}; int yes = 1; sock_peer = pico_socket_accept(s, &orig, &port); pico_ipv4_to_string(peer, orig.addr); ZF_LOGD("Connection established with %s:%d.\n", peer, short_be(port)); pico_socket_setoption(sock_peer, PICO_TCP_NODELAY, &yes); /* Set keepalive options - from picoTCP documentation */ ka_val = 5; pico_socket_setoption(sock_peer, PICO_SOCKET_OPT_KEEPCNT, &ka_val); ka_val = 30000; pico_socket_setoption(sock_peer, PICO_SOCKET_OPT_KEEPIDLE, &ka_val); ka_val = 5000; pico_socket_setoption(sock_peer, PICO_SOCKET_OPT_KEEPINTVL, &ka_val); } if (ev & PICO_SOCK_EV_FIN) { ZF_LOGD("Socket closed. Exit normally. \n"); } if (ev & PICO_SOCK_EV_ERR) { ZF_LOGD("Socket error received: %s. Bailing out.\n", strerror(pico_err)); } if (ev & PICO_SOCK_EV_CLOSE) { ZF_LOGD("Socket received close from peer.\n"); pico_socket_shutdown(s, PICO_SHUT_WR); } if (ev & PICO_SOCK_EV_WR) { ZF_LOGD("TCP Write ack\n"); } }
void cb_tcpclient(uint16_t ev, struct pico_socket *s) { static int w_size = 0; static int r_size = 0; static int closed = 0; int r, w; char buf[1024]; ZF_LOGD("tcpclient> wakeup %lu, event %u\n", count, ev); if (ev & PICO_SOCK_EV_RD) { do { r = pico_socket_read(s, buf, 1024); if (r > 0) { printf("READ >>"); fwrite(buf, r, 1, stdout); } if (r < 0){ ZF_LOGF("READ ERROR\n"); } } while(r > 0); } if (ev & PICO_SOCK_EV_CONN) { ZF_LOGD("Connection established with server.\n"); } if (ev & PICO_SOCK_EV_FIN) { ZF_LOGD("Socket closed. Exit normally. \n"); } if (ev & PICO_SOCK_EV_ERR) { ZF_LOGD("Socket error received: %s. Bailing out.\n", strerror(pico_err)); } if (ev & PICO_SOCK_EV_CLOSE) { ZF_LOGD("Socket received close from peer - Wrong case if not all client data sent!\n"); pico_socket_close(s); } if (ev & PICO_SOCK_EV_WR) { ZF_LOGD("Pico socket write cb\n"); } }
int run() { ZF_LOGD("Begin TCP server component"); }