static int ipc_caller(seL4_Word ep0, seL4_Word ep1, seL4_Word word_bits, seL4_Word arg4) { /* Let our parent know we are ready. */ seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1); seL4_SetMR(0, READY_MAGIC); seL4_Send(ep0, tag); /* * The parent has changed our cspace on us. Check that it makes sense. * * Basically the entire cspace should be empty except for the cap at ep0. * We should still test that various points in the cspace resolve correctly. */ /* Check that none of the typical endpoints are valid. */ for (unsigned long i = 0; i < word_bits; i++) { seL4_MessageInfo_ptr_new(&tag, 0, 0, 0, 0); tag = seL4_Call(i, tag); test_assert(seL4_MessageInfo_get_label(tag) == seL4_InvalidCapability); } /* Check that changing one bit still gives an invalid cap. */ for (unsigned long i = 0; i < word_bits; i++) { seL4_MessageInfo_ptr_new(&tag, 0, 0, 0, 0); tag = seL4_Call(ep1 ^ BIT(i), tag); test_assert(seL4_MessageInfo_get_label(tag) == seL4_InvalidCapability); } /* And we're done. This should be a valid cap and get us out of here! */ seL4_MessageInfo_ptr_new(&tag, 0, 0, 0, 1); seL4_SetMR(0, SUCCESS_MAGIC); seL4_Send(ep1, tag); 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(); }
/* IRQ handler thread. Wait on a notification object for IRQs. When one arrives, send a * synchronous message to the registered endpoint. If no synchronous endpoint was * registered, call the appropriate handler function directly (must be thread safe) */ static void _irq_thread_entry(struct irq_server_thread* st) { seL4_CPtr sep; seL4_CPtr notification; uintptr_t node_ptr; seL4_Word label; sep = st->delivery_sep; notification = st->node->notification; node_ptr = (uintptr_t)st->node; label = st->label; DIRQSERVER("thread started. Waiting on endpoint %d\n", notification); while (1) { seL4_Word badge; seL4_Wait(notification, &badge); assert(badge != 0); if (sep != seL4_CapNull) { /* Synchronous endpoint registered. Send IPC */ seL4_MessageInfo_t info = seL4_MessageInfo_new(label, 0, 0, 2); seL4_SetMR(0, badge); seL4_SetMR(1, node_ptr); seL4_Send(sep, info); } else { /* No synchronous endpoint. Call the handler directly */ irq_server_node_handle_irq(st->node, badge); } } }
/* override abort, called by exit (and assert fail) */ void abort(void) { /* send back a failure */ seL4_MessageInfo_t info = seL4_MessageInfo_new(seL4_NoFault, 0, 0, 1); seL4_SetMR(0, -1); seL4_Send(endpoint, info); /* we should not get here */ assert(0); while (1); }
void rpc_sv_reply(void* cl) { if (rpc_sv_skip_reply(cl)) return; seL4_CPtr reply_endpoint = rpc_sv_get_reply_endpoint(cl); seL4_MessageInfo_t reply = seL4_MessageInfo_new(0, 0, _rpc_cp, _rpc_mr); if (reply_endpoint) { seL4_Send(reply_endpoint, reply); } else { seL4_Reply(reply); } }
/* * Test threads at all possible priorities, and that they get scheduled in the * correct order. */ static int prio_test_func(seL4_Word my_prio, seL4_Word* last_prio, seL4_CPtr ep) { test_check(*last_prio - 1 == my_prio); *last_prio = my_prio; /* Unsuspend the top thread if we are the last one. */ if (my_prio == MIN_PRIO) { seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Send(ep, tag); } return 0; }
void ffiseL4_Send(unsigned char *c, long clen, unsigned char *a, long alen) { seL4_CPtr ep; int offset = 1; memcpy(&ep, a + offset, sizeof(ep)); offset += sizeof(ep); seL4_Word len; memcpy(&len, a + offset, sizeof(len)); offset += sizeof(len); memcpy(&seL4_GetIPCBuffer()->msg[0], a + offset, len); seL4_Send( ep, seL4_MessageInfo_new(0, 0, 0, ROUND_UP_UNSAFE(len, sizeof(seL4_Word)) / sizeof(seL4_Word))); a[0] = FFI_SUCCESS; }
/* map the init data into the process, and send the address via ipc */ static void * send_init_data(env_t env, seL4_CPtr endpoint, sel4utils_process_t *process) { /* map the cap into remote vspace */ void *remote_vaddr = vspace_map_pages(&process->vspace, &env->init_frame_cap_copy, NULL, seL4_AllRights, 1, PAGE_BITS_4K, 1); assert(remote_vaddr != 0); /* now send a message telling the process what address the data is at */ seL4_MessageInfo_t info = seL4_MessageInfo_new(seL4_NoFault, 0, 0, 1); seL4_SetMR(0, (seL4_Word) remote_vaddr); seL4_Send(endpoint, info); return remote_vaddr; }
/* avoids the need for sync primitives */ int mmap_swap (int direction, vaddr_t vaddr, struct frameinfo* frame, void* callback, struct pawpaw_event* evt) { seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 6); seL4_SetMR (0, MMAP_REQUEST); seL4_SetMR (1, direction); seL4_SetMR (2, vaddr); seL4_SetMR (3, (seL4_Word)frame); seL4_SetMR (4, (seL4_Word)callback); seL4_SetMR (5, (seL4_Word)evt); /* note: cannot be a Call since svc_mmap might require the root server * to be free to handle some of its own requests, eg sbrk */ seL4_Send (_mmap_ep, msg); return true; }
static void _sos_VMFaultHandler_reply(void* token, int err){ dprintf(3, "sos_vmf_reply called\n"); VMF_cont_t *cont= (VMF_cont_t*)token; if(err){ dprintf(3, "sos_vmf received an err\n"); } if (!is_proc_alive(cont->pid)) { cspace_free_slot(cur_cspace, cont->reply_cap); free(cont); return; } /* Flush the i-cache. Ideally, this should only be done when faulting on text segment */ //if (cont->is_code) { if (!err) { seL4_Word vpage = PAGE_ALIGN(cont->vaddr); int x = PT_L1_INDEX(vpage); int y = PT_L2_INDEX(vpage); seL4_Word kvaddr = (cont->as->as_pd_regs[x][y] & PTE_KVADDR_MASK); seL4_CPtr kframe_cap; err = frame_get_cap(kvaddr, &kframe_cap); //assert(!err); // This kvaddr is ready to use, there should be no error seL4_ARM_Page_Unify_Instruction(kframe_cap, 0, PAGESIZE); } //} /* If there is an err here, it is not the process's fault * It is either the kernel running out of memory or swapping doesn't work */ seL4_MessageInfo_t reply = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Send(cont->reply_cap, reply); cspace_free_slot(cur_cspace, cont->reply_cap); free(cont); set_cur_proc(PROC_NULL); }
static int ipc_test_helper_3(ipc_test_data_t *data) { seL4_MessageInfo_t tag; int last_spins, last_bounces, result = 0; /* This test starts here. */ /* TEST PART 1 */ /* Perform a send to a thread 1. It is not yet waiting. */ CHECK_STEP(ipc_test_step, 0); seL4_MessageInfo_ptr_new(&tag, 0, 0, 0, 20); for (int i = 0; i < seL4_MessageInfo_get_length(tag); i++) { seL4_SetMR(i, i); } last_spins = data->spins; last_bounces = data->bounces; seL4_Send(data->ep1, tag); /* We block, causing thread 2 to spin for a while, before it calls the * bouncer thread 0, which finally lets thread 1 run and reply to us. */ CHECK_STEP(ipc_test_step, 2); CHECK_TESTCASE(result, data->spins - last_spins == 1); CHECK_TESTCASE(result, data->bounces - last_bounces == 0); /* Now bounce ourselves, to ensure that thread 1 can check its stuff. */ seL4_MessageInfo_ptr_set_length(&tag, 0); seL4_Call(data->ep0, tag); /* Two bounces - us and thread 1. */ CHECK_TESTCASE(result, data->spins - last_spins == 2); CHECK_TESTCASE(result, data->bounces - last_bounces == 2); CHECK_STEP(ipc_test_step, 4); /* TEST PART 2 */ /* Perform a send to a thread 1, which is already waiting. */ /* Bounce first to let thread prepare. */ last_spins = data->spins; last_bounces = data->bounces; seL4_MessageInfo_ptr_set_length(&tag, 0); seL4_Call(data->ep0, tag); CHECK_STEP(ipc_test_step, 6); /* Do the send. */ seL4_MessageInfo_ptr_set_length(&tag, 19); for (int i = 0; i < seL4_MessageInfo_get_length(tag); i++) { seL4_SetMR(i, i); } seL4_Send(data->ep1, tag); CHECK_STEP(ipc_test_step, 7); /* Bounce to let thread 1 check again. */ seL4_MessageInfo_ptr_set_length(&tag, 0); seL4_Call(data->ep0, tag); CHECK_STEP(ipc_test_step, 9); /* Five bounces in total. */ CHECK_TESTCASE(result, data->spins - last_spins == 2); CHECK_TESTCASE(result, data->bounces - last_bounces == 5); return result; }
int main(int argc, char **argv) { test_init_data_t *init_data; struct env env; assert(argc >= 2); /* in order to have some shitty almost-fork-like semantics * main can get run multiple times. Look in src/helpers.c * for where this is used. Just means we check the first * arg, and if not NULL jmp to it */ void (*helper_thread)(int argc,char **argv) = (void(*)(int, char**))atol(argv[1]); if (helper_thread) { helper_thread(argc, argv); } /* parse args */ assert(argc == 3); endpoint = (seL4_CPtr) atoi(argv[2]); /* read in init data */ init_data = receive_init_data(endpoint); /* configure env */ env.cspace_root = init_data->root_cnode; env.page_directory = init_data->page_directory; env.endpoint = endpoint; env.priority = init_data->priority; env.cspace_size_bits = init_data->cspace_size_bits; env.tcb = init_data->tcb; env.domain = init_data->domain; #ifndef CONFIG_KERNEL_STABLE env.asid_pool = init_data->asid_pool; env.asid_ctrl = init_data->asid_ctrl; #endif /* CONFIG_KERNEL_STABLE */ #ifdef CONFIG_IOMMU env.io_space = init_data->io_space; #endif env.num_regions = init_data->num_elf_regions; memcpy(env.regions, init_data->elf_regions, sizeof(sel4utils_elf_region_t) * env.num_regions); /* initialse cspace, vspace and untyped memory allocation */ init_allocator(&env, init_data); /* initialise the timer */ init_timer(&env, init_data); /* find the test */ testcase_t *test = find_test(init_data->name); /* run the test */ int result = 0; if (test) { printf("Running test %s (%s)\n", test->name, test->description); result = test->function(&env); } else { result = FAILURE; ZF_LOGF("Cannot find test %s\n", init_data->name); } printf("Test %s %s\n", init_data->name, result == SUCCESS ? "passed" : "failed"); /* send our result back */ seL4_MessageInfo_t info = seL4_MessageInfo_new(seL4_NoFault, 0, 0, 1); seL4_SetMR(0, result); seL4_Send(endpoint, info); /* It is expected that we are torn down by the test driver before we are * scheduled to run again after signalling them with the above send. */ assert(!"unreachable"); return 0; }
/* sends off a frame to the relevant swap file (in or out) * * returns True if the root server needs to be notified immediately (ie not * waiting for an async reply */ static int mmap_queue_schedule (int direction, vaddr_t vaddr, struct frameinfo *frame, void* callback, struct pawpaw_event* evt) { struct mmap_queue_item* q = mmap_queue_new (frame, callback, evt); if (!q) { return false; } //assert (frame); if (direction == PAGE_SWAP_IN) { assert (frame->file); assert (frame->file->file); /* FIXME: seriously this needs work */ struct seen_item *item = regd_caps; while (item) { if (item->cap == frame->file->file) { break; } item = item->next; } /* register with the filesystem for async notifications if this is our * first time with this file */ if (!item) { seL4_MessageInfo_t reg_msg = seL4_MessageInfo_new (0, 0, 1, 1); seL4_CPtr their_cap = cspace_mint_cap (cur_cspace, cur_cspace, _mmap_ep, seL4_AllRights, seL4_CapData_Badge_new ((seL4_Word)frame)); assert (their_cap); seL4_SetMR (0, VFS_REGISTER_CAP); seL4_SetCap (0, their_cap); seL4_Call (frame->file->file, reg_msg); seL4_Word id = seL4_GetMR (0); assert (id > 0); item = malloc (sizeof (struct seen_item)); assert (item); item->cap = frame->file->file; item->id = id; item->next = regd_caps; regd_caps = item; } seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 1, 4); seL4_Word id = cid_next (); maps_append (id, ((thread_t)evt->args[1])->pid, vaddr); /* create a "valid badge" in the badgemap so we can mount the * shared buffer */ seL4_CPtr badge_cap = cspace_mint_cap ( cur_cspace, cur_cspace, _badgemap_ep, seL4_AllRights, seL4_CapData_Badge_new (id)); assert (badge_cap); assert (frame->file); msg = seL4_MessageInfo_new (0, 0, 1, 7); seL4_SetCap (0, badge_cap); seL4_SetMR (0, VFS_READ_OFFSET); seL4_SetMR (1, id); seL4_SetMR (2, frame->file->load_length); seL4_SetMR (3, frame->file->file_offset); seL4_SetMR (4, frame->file->load_offset); seL4_SetMR (5, item->id); /* async ID */ seL4_SetMR (6, (seL4_Word)frame); /* use frame ptr as "event id" */ seL4_Send (frame->file->file, msg); /* and we go back to waiting on our EP */ } else if (direction == PAGE_SWAP_OUT) { seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 1, 4); /* FIXME: needs to be cleaned up on successful swap */ seL4_Word id = cid_next (); maps_append (id, 0, vaddr); /* create a "valid badge" in the badgemap so we can mount the shared * buffer */ seL4_CPtr badge_cap = cspace_mint_cap (cur_cspace, cur_cspace, _badgemap_ep, seL4_AllRights, seL4_CapData_Badge_new (id)); assert (badge_cap); seL4_Word page_id = last_page_id * PAGE_SIZE; last_page_id++; seL4_Word wrote = 0; while (wrote < PAGE_SIZE) { msg = seL4_MessageInfo_new (0, 0, 1, 7); seL4_SetCap (0, badge_cap); seL4_SetMR (0, VFS_WRITE_OFFSET); seL4_SetMR (1, id); seL4_SetMR (2, PAGE_SIZE - wrote); /* write whole page out */ seL4_SetMR (3, page_id + wrote); /* file offset */ seL4_SetMR (4, wrote); /* load into start of share */ //seL4_SetMR (5, swap_id); /* async ID - NOT USED */ seL4_SetMR (6, (seL4_Word)frame); /* and write it out */ seL4_Call (swap_cap, msg); seL4_Word wrote_this_call = seL4_GetMR (0); assert (wrote_this_call >= 0); wrote += wrote_this_call; } cspace_delete_cap (cur_cspace, badge_cap); /* memory map it */ frame->file = frame_create_mmap (swap_cap, 0, page_id, PAGE_SIZE); assert (frame->file); mmap_move_done (q); return true; /* and we go back to waiting on our EP */ } else if (direction == BUFFER_OPEN_LOAD) { seL4_Word share_id = cid_next (); maps_append (share_id, 0, vaddr); /* create a "valid badge" in the badgemap so we can mount the shared * buffer */ seL4_CPtr badge_cap = cspace_mint_cap (cur_cspace, cur_cspace, _badgemap_ep, seL4_AllRights, seL4_CapData_Badge_new (share_id)); assert (badge_cap); seL4_CPtr recv_cap = cspace_alloc_slot (cur_cspace); assert (recv_cap); seL4_SetCapReceivePath (cur_cspace->root_cnode, recv_cap, CSPACE_DEPTH); printf ("OK, asking VFS to open our file '%s'\n", (char*)vaddr); seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 1, 4); seL4_SetCap (0, badge_cap); seL4_SetMR (0, VFS_OPEN); seL4_SetMR (1, share_id); seL4_SetMR (2, FM_READ); seL4_SetMR (3, 0); /* XXX: hack of the century - should really ask VFS async * for cap */ seL4_CPtr nfs_fs_cap = service_lookup ("fs_nfs"); while (!nfs_fs_cap) { printf ("failed to find nfs service\n"); nfs_fs_cap = service_lookup ("fs_nfs"); //return false; } printf ("calling on %d\n", nfs_fs_cap); seL4_MessageInfo_t reply = seL4_Call (nfs_fs_cap, msg); if (seL4_GetMR (0) != 0) { printf ("%s: failed to open file\n", __FUNCTION__); //return false; mmap_move_done (q); q->frame = NULL; return true; } assert (seL4_MessageInfo_get_capsUnwrapped (reply) == 0); if (seL4_MessageInfo_get_extraCaps (reply) != 1) { /* could not find file */ printf ("%s: did not have cap\n", __FUNCTION__); return false; } printf ("yum, setting evt arg\n"); evt->args[2] = recv_cap; /* then, load in the first page worth of the file into kmem, so we * can read the headers we need */ printf ("sweeto, trying to read in data...\n"); msg = seL4_MessageInfo_new (0, 0, 1, 3); seL4_SetCap (0, badge_cap); seL4_SetMR (0, VFS_READ); seL4_SetMR (1, share_id); seL4_SetMR (2, PAGE_SIZE); //seL4_SetMR (3, 0); /* offset */ printf ("ASKING TO READ FILE\n"); seL4_Call (recv_cap, msg); if (seL4_GetMR (0) <= 0) { printf ("%s: read was empty/failed\n", __FUNCTION__); //return NULL; return false; } printf("read was ok\n"); mmap_move_done (q); return true; } return false; }
void sos_VMFaultHandler(seL4_CPtr reply_cap, seL4_Word fault_addr, seL4_Word fsr, bool is_code){ dprintf(3, "sos vmfault handler \n"); int err; dprintf(3, "sos vmfault handler, getting as \n"); addrspace_t *as = proc_getas(); dprintf(3, "sos vmfault handler, gotten as \n"); if (as == NULL) { dprintf(3, "app as is NULL\n"); /* Kernel is probably failed when bootstraping */ set_cur_proc(PROC_NULL); cspace_free_slot(cur_cspace, reply_cap); return; } region_t *reg; /* Is this a segfault? */ if (_check_segfault(as, fault_addr, fsr, ®)) { dprintf(3, "vmf: segfault\n"); proc_destroy(proc_get_id()); set_cur_proc(PROC_NULL); cspace_free_slot(cur_cspace, reply_cap); return; } /* * If it comes here, this must be a valid address Therefore, this page is * either swapped out has never been mapped in */ VMF_cont_t *cont = malloc(sizeof(VMF_cont_t)); if (cont == NULL) { dprintf(3, "vmfault out of mem\n"); /* We cannot handle the fault but the process still can run * There will be more faults coming though */ set_cur_proc(PROC_NULL); seL4_MessageInfo_t reply = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Send(reply_cap, reply); cspace_free_slot(cur_cspace, reply_cap); return; } cont->reply_cap = reply_cap; cont->as = as; cont->vaddr = fault_addr; cont->is_code = is_code; cont->reg = reg; cont->pid = proc_get_id(); /* Check if this page is an new, unmaped page or is it just swapped out */ if (sos_page_is_inuse(as, fault_addr)) { if (sos_page_is_swapped(as, fault_addr)) { dprintf(3, "vmf tries to swapin\n"); /* This page is swapped out, we need to swap it back in */ err = swap_in(cont->as, cont->reg->rights, cont->vaddr, cont->is_code, _sos_VMFaultHandler_reply, cont); if (err) { _sos_VMFaultHandler_reply((void*)cont, err); return; } return; } else { if (sos_page_is_locked(as, fault_addr)) { dprintf(3, "vmf page is locked\n"); _sos_VMFaultHandler_reply((void*)cont, EFAULT); return; } dprintf(3, "vmf second chance mapping page back in\n"); err = _set_page_reference(cont->as, cont->vaddr, cont->reg->rights); _sos_VMFaultHandler_reply((void*)cont, err); return; } } else { /* This page has never been mapped, so do that and return */ dprintf(3, "vmf tries to map a page\n"); inc_proc_size_proc(cur_proc()); err = sos_page_map(proc_get_id(), as, fault_addr, reg->rights, _sos_VMFaultHandler_reply, (void*)cont, false); if(err){ dec_proc_size_proc(cur_proc()); _sos_VMFaultHandler_reply((void*)cont, err); } return; } /* Otherwise, this is not handled */ dprintf(3, "vmf error at the end\n"); _sos_VMFaultHandler_reply((void*)cont, EFAULT); return; }