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(); }
pid_t my_id(void) { seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 1); seL4_SetMR (0, SYSCALL_PROCESS_GETPID); seL4_Call (PAPAYA_SYSCALL_SLOT, msg); return seL4_GetMR (0); }
int call_func_ta(int ta_num,int func_id,int simp_arg,void *data,size_t size,seL4_Word *res){ int length = size/(double)sizeof(seL4_Word); if((length+5) > seL4_MsgMaxLength){ printf("Params too large. operation failed\n"); return -1; }else{ seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 5+length); seL4_SetTag(tag); seL4_SetMR(0, CALL_FUNC_CMD); seL4_SetMR(1, ta_num); seL4_SetMR(2,func_id); seL4_SetMR(3,simp_arg); seL4_SetMR(4,length); seL4_Word* blockptr = (seL4_Word*)data; for(int i =0; i < length;++i){ seL4_SetMR(i+5,*blockptr); blockptr++; } seL4_Call(TEE_EP_CPTR,tag); int res_val = seL4_GetMR(0); if(res != NULL){ int len = seL4_GetMR(1); for(int i =0; i < len;++i){ res[i] = seL4_GetMR(i+2); } } return res_val; } }
// Block a thread forever // we do this by making an unimplemented system call. static void thread_block(void){ seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1); seL4_SetTag(tag); seL4_SetMR(0, 100); seL4_Call(SYSCALL_ENDPOINT_SLOT, tag); }
int read (fildes_t file, char *buf, size_t nbyte) { if (nbyte >= (1 << 12)) { return -1; /* FIXME: crappy limitation */ } struct sos_fhandle* fh = sos_lookup_fhandle (file); if (!fh) { return -1; } seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, pawpaw_share_attach (fh->share), 3); //seL4_SetCap (0, fh->share->cap); seL4_SetMR (0, VFS_READ); seL4_SetMR (1, fh->share->id); seL4_SetMR (2, nbyte); seL4_Call (fh->cap, msg); int read = seL4_GetMR (0); if (read > 0) { memcpy (buf, fh->share->buf, read); } return read; }
int process_delete(pid_t pid) { seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 2); seL4_SetMR (0, SYSCALL_PROCESS_DESTROY); seL4_SetMR (1, pid); seL4_Call (PAPAYA_SYSCALL_SLOT, msg); return seL4_GetMR (0); }
pid_t process_wait(pid_t pid) { seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 2); seL4_SetMR (0, SYSCALL_PROCESS_WAIT); seL4_SetMR (1, pid); seL4_Call (PAPAYA_SYSCALL_SLOT, msg); return seL4_GetMR (0); }
/** * Signal that a thrd has finished */ static void signal_thrd_finished(seL4_CPtr local_endpoint, int val) { seL4_MessageInfo_t info = seL4_MessageInfo_new(0, 0, 0, 1); seL4_SetMR(0, val); seL4_Call(local_endpoint, info); assert(0); while (1); }
/* sends: * vaddr in process address space of processes buffer (should do map-in-out) * maximum number to place in buffer */ int process_status(process_t *processes, unsigned max) { seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 3); seL4_SetMR (0, SYSCALL_PROCESS_SEND_STATUS); seL4_SetMR (1, (seL4_Word)processes); seL4_SetMR (2, max); seL4_Call (PAPAYA_SYSCALL_SLOT, msg); return seL4_GetMR (0); }
int rpc_call_server() { seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, _rpc_cp, _rpc_mr); int ept = rpc_get_endpoint(_rpc_label); _rpc_minfo = seL4_Call(ept, tag); rpc_reset_contents(NULL); return 0; }
pid_t process_create_args_env (const char* path, const char* argv[], const int argc, const char* envv[], const int envc) { seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 3); seL4_SetMR (0, SYSCALL_PROCESS_CREATE); seL4_SetMR (1, (seL4_Word)path); seL4_SetMR (2, (seL4_Word)argv); char* seL4_SetMR (3, argc + envc) seL4_Call (PAPAYA_SYSCALL_SLOT, msg); return seL4_GetMR (0); }
pid_t process_create_args (const char* path, const char* argv[]) { #endif seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 3); seL4_SetMR (0, SYSCALL_PROCESS_CREATE); seL4_SetMR (1, (seL4_Word)path); seL4_SetMR (2, strlen (path)); //seL4_SetMR (2, (seL4_Word)argv); //seL4_SetMR (3, ) seL4_Call (PAPAYA_SYSCALL_SLOT, msg); return seL4_GetMR (0); }
static int call_func(seL4_CPtr ep, seL4_Word msg, volatile seL4_Word *done, seL4_Word arg3) { seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1); /* Send the given message once. */ seL4_SetMR(0, msg); tag = seL4_Call(ep, tag); test_check(seL4_MessageInfo_get_length(tag) == 1); test_check(seL4_GetMR(0) == ~msg); *done = 0; /* Send the given message again - should (eventually) fault this time. */ seL4_SetMR(0, msg); tag = seL4_Call(ep, tag); /* The call should fail. */ test_check(seL4_MessageInfo_get_label(tag) == seL4_InvalidCapability); *done = 1; return sel4test_get_result(); }
static int ep_test_func(seL4_CPtr sync_ep, seL4_CPtr test_ep, volatile seL4_Word *status, seL4_Word arg4) { seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Word sender_badge; while (1) { seL4_Recv(sync_ep, &sender_badge); /* Hit up the test end point */ seL4_MessageInfo_t reply = seL4_Call(test_ep, tag); /* See what the status was */ *status = !!(seL4_MessageInfo_get_label(reply) != seL4_InvalidCapability); /* Reply */ seL4_Reply(tag); } return sel4test_get_result(); }
int stat (const char *path, stat_t *buf) { seL4_MessageInfo_t msg; if (!vfs_ep) { vfs_ep = pawpaw_service_lookup ("svc_vfs"); } struct pawpaw_share* share = pawpaw_share_new (); if (!share) { return -1; } memset (share->buf, 0, PAPAYA_IPC_PAGE_SIZE); if (path && path[0] != '/') { strcpy (share->buf, cwd); int cwdlen = strlen (cwd); if (cwdlen > 0 && cwd[cwdlen - 1] != '/') { strcat (share->buf, "/"); } strcat (share->buf, path); /* XXX: check if buffer overflows */ } else { strcpy (share->buf, path); } msg = seL4_MessageInfo_new (0, 0, 1, 2); seL4_CPtr recv_cap = pawpaw_cspace_alloc_slot (); if (!recv_cap) { pawpaw_share_unmount (share); return -1; } seL4_SetCapReceivePath (PAPAYA_ROOT_CNODE_SLOT, recv_cap, PAPAYA_CSPACE_DEPTH); seL4_SetCap (0, share->cap); seL4_SetMR (0, VFS_STAT); seL4_SetMR (1, share->id); seL4_Call (vfs_ep, msg); int status = seL4_GetMR (0); if (status == 0) { memcpy (buf, share->buf, sizeof (stat_t)); } pawpaw_share_unmount (share); return status; }
long sys_brk(va_list ap) { //printf("sysbrk\n"); uintptr_t newbrk = va_arg(ap, uintptr_t); //printf("newbrk before = %d\n",newbrk); seL4_MessageInfo_t tag = seL4_MessageInfo_new(seL4_NoFault, 0, 0, 2); seL4_SetTag(tag); seL4_SetMR(0, SOS_SYSCALL_SYSBRK); seL4_SetMR(1, newbrk); seL4_MessageInfo_t message = seL4_Call(SYSCALL_ENDPOINT_SLOT, tag); newbrk = seL4_MessageInfo_get_label(message); //printf("newbrk result = %d\n",newbrk); return newbrk; }
int start_ta(char *ta_name){ seL4_Word msg; int arg_len = strlen(ta_name); seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 2+arg_len); seL4_SetTag(tag); seL4_SetMR(0, START_TA_CMD); printf("client-os: Calling TEE-CONTAINER to start TA \n"); seL4_Word *ptr = (seL4_Word*)ta_name; for(int i=0;i < arg_len;++i){ seL4_SetMR(i+2,*ptr); ptr++; } ptr = ta_name; seL4_SetMR(1,arg_len); seL4_Call(TEE_EP_CPTR,tag); msg = seL4_GetMR(0); return msg; }
void serial_server_disconnect(serial_client_context_t *conn) { seL4_MessageInfo_t tag; if (conn == NULL) { return; } seL4_SetMR(SSMSGREG_FUNC, FUNC_DISCONNECT_REQ); tag = seL4_MessageInfo_new(0, 0, 0, SSMSGREG_DISCONNECT_REQ_END); tag = seL4_Call(conn->badged_server_ep_cspath.capPtr, tag); if (seL4_GetMR(SSMSGREG_FUNC) != FUNC_DISCONNECT_ACK) { ZF_LOGE(SERSERVC"disconnect: reply message was not a DISCONNECT_ACK " "as expected."); } }
int serial_server_kill(serial_client_context_t *conn) { seL4_MessageInfo_t tag; if (conn == NULL) { return seL4_InvalidArgument; } seL4_SetMR(SSMSGREG_FUNC, FUNC_KILL_REQ); tag = seL4_MessageInfo_new(0, 0, 0, SSMSGREG_KILL_REQ_END); tag = seL4_Call(conn->badged_server_ep_cspath.capPtr, tag); if (seL4_GetMR(SSMSGREG_FUNC) != FUNC_KILL_ACK) { ZF_LOGE(SERSERVC"kill: Reply message was not a KILL_ACK as expected."); return seL4_IllegalOperation; } return seL4_MessageInfo_get_label(tag); }
int getdirent (int pos, char *path, size_t nbyte) { seL4_MessageInfo_t msg; if (!vfs_ep) { vfs_ep = pawpaw_service_lookup ("svc_vfs"); } struct pawpaw_share* share = pawpaw_share_new (); if (!share) { return -1; } msg = seL4_MessageInfo_new (0, 0, 1, 4); seL4_CPtr recv_cap = pawpaw_cspace_alloc_slot (); if (!recv_cap) { pawpaw_share_unmount (share); return -1; } seL4_SetCapReceivePath (PAPAYA_ROOT_CNODE_SLOT, recv_cap, PAPAYA_CSPACE_DEPTH); seL4_SetCap (0, share->cap); memset (share->buf, 0, PAPAYA_IPC_PAGE_SIZE); strcpy (share->buf, cwd); seL4_SetMR (0, VFS_LISTDIR); seL4_SetMR (1, share->id); seL4_SetMR (2, pos); seL4_SetMR (3, nbyte); seL4_Call (vfs_ep, msg); int read = seL4_GetMR (0); if (read >= 0) { memcpy (path, share->buf, nbyte); pawpaw_share_unmount (share); return read; } else { pawpaw_share_unmount (share); return -1; } }
static int ipc_test_helper_2(ipc_test_data_t *data) { /* We are a spinner thread. Our job is to do spin, and occasionally bounce * to thread 0 to let other code execute. */ while (1) { /* Ensure nothing happens whilst we are busy. */ int last_step = ipc_test_step; for (int i = 0; i < 100000; i++) { asm volatile (""); } test_check(last_step == ipc_test_step); data->spins++; /* Bounce. */ seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); seL4_Call(data->ep0, tag); } return 0; }
int close(fildes_t file) { struct sos_fhandle* fh = sos_lookup_fhandle (file); if (!fh) { return -1; } seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, 0, 1); seL4_SetMR (0, VFS_CLOSE); seL4_Call (fh->cap, msg); if (seL4_GetMR (0) == 0) { //pawpaw_cspace_free_slot (fh->cap); /* should DELETE the slot, then free */ //pawpaw_share_unmount (fh->share); /* FIXME: fix up list */ //free (fh); return 0; } else { return -1; } }
/* Attempt single write, without retrying */ size_t _sos_write(void *vData, size_t count) { seL4_Word *realdata = (seL4_Word*) vData; seL4_IPCBuffer *buf = seL4_GetIPCBuffer(); seL4_Word len = 2 + DIVROUND(count, 4); seL4_Word real_len = MIN(seL4_MsgMaxLength, len); size_t real_count = MIN(count, (seL4_MsgMaxLength - 2) * 4); /* Set up syscall parameters */ buf->msg[0] = SOS_SYSCALL_WRITE_CONSOLE; buf->msg[1] = real_count; int i; for (i = 2; i < len; i++) { buf->msg[i] = realdata[i - 2]; } /* Fire off syscall and wait for reply */ seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, real_len); seL4_Call(SYSCALL_ENDPOINT_SLOT, tag); return seL4_GetMR(0); }
/** Performs the IPC register setup for a write() call to the server. * * The Server's ABI for the write() request has changed a little: the server * now returns the number of bytes it wrote out to the serial in a msg-reg, * aside from also returning an error code in the "label" of the header. * * @param conn Initialized connection token returned by * serial_server_client_connect(). * @param len length of the data in the buffer. * @param server_nbytes_written The value the server reports that it actually * wrote to the serial device. * @return 0 on success, or integer error value on error. */ static ssize_t serial_server_write_ipc_invoke(serial_client_context_t *conn, ssize_t len) { seL4_MessageInfo_t tag; seL4_SetMR(SSMSGREG_FUNC, FUNC_WRITE_REQ); seL4_SetMR(SSMSGREG_WRITE_REQ_BUFF_LEN, len); tag = seL4_MessageInfo_new(0, 0, 0, SSMSGREG_WRITE_REQ_END); tag = seL4_Call(conn->badged_server_ep_cspath.capPtr, tag); if (seL4_GetMR(SSMSGREG_FUNC) != FUNC_WRITE_ACK) { ZF_LOGE(SERSERVC"printf: Reply message was not a WRITE_ACK as " "expected."); return - seL4_IllegalOperation; } if (seL4_MessageInfo_get_label(tag) != 0) { return - seL4_MessageInfo_get_label(tag); } return seL4_GetMR(SSMSGREG_WRITE_ACK_N_BYTES_WRITTEN); }
static int ipc_test_helper_1(ipc_test_data_t *data) { seL4_Word sender_badge = 0; seL4_MessageInfo_t tag; int result = 0; /* TEST PART 1 */ /* Receive a pending send. */ CHECK_STEP(ipc_test_step, 1); tag = seL4_Recv(data->ep1, &sender_badge); /* As soon as the wait is performed, we should be preempted. */ /* Thread 3 will give us a chance to check our message. */ CHECK_STEP(ipc_test_step, 3); CHECK_TESTCASE(result, seL4_MessageInfo_get_length(tag) == 20); for (int i = 0; i < seL4_MessageInfo_get_length(tag); i++) { CHECK_TESTCASE(result, seL4_GetMR(i) == i); } /* Now we bounce to allow thread 3 control again. */ seL4_MessageInfo_ptr_set_length(&tag, 0); seL4_Call(data->ep0, tag); /* TEST PART 2 */ /* Receive a send that is not yet pending. */ CHECK_STEP(ipc_test_step, 5); tag = seL4_Recv(data->ep1, &sender_badge); CHECK_STEP(ipc_test_step, 8); CHECK_TESTCASE(result, seL4_MessageInfo_get_length(tag) == 19); for (int i = 0; i < seL4_MessageInfo_get_length(tag); i++) { CHECK_TESTCASE(result, seL4_GetMR(i) == i); } return result; }
int write(fildes_t file, const char *buf, size_t nbyte) { if (nbyte >= (1 << 12)) { return -1; /* FIXME: crappy limitation */ } struct sos_fhandle* fh = sos_lookup_fhandle (file); if (!fh) { return -1; } memcpy (fh->share->buf, buf, nbyte); seL4_MessageInfo_t msg = seL4_MessageInfo_new (0, 0, pawpaw_share_attach (fh->share), 3); //seL4_SetCap (0, fh->share->cap); seL4_SetMR (0, VFS_WRITE); seL4_SetMR (1, fh->share->id); seL4_SetMR (2, nbyte); seL4_Call (fh->cap, msg); int wrote = seL4_GetMR (0); return wrote; }
int main(void) { int error; /* give us a name: useful for debugging if the thread faults */ name_thread(seL4_CapInitThreadTCB, "hello-3"); /* get boot info */ info = seL4_GetBootInfo(); /* print out bootinfo */ print_bootinfo(info); /* get our cspace root cnode */ seL4_CPtr cspace_cap; cspace_cap = seL4_CapInitThreadCNode; /* get our vspace root page directory */ seL4_CPtr pd_cap; pd_cap = seL4_CapInitThreadPD; /* TODO 1: Find free cap slots for the caps to the: * - tcb * - ipc frame * - endpoint * - badged endpoint * - page table * hint: The bootinfo struct contains a range of free cap slot indices. */ /* decide on slots to use based on what is free */ seL4_CPtr tcb_cap = ???; seL4_CPtr ipc_frame_cap = ???; ep_cap = ???; badged_ep_cap = ???; seL4_CPtr page_table_cap = ???; /* get an untyped to retype into all the objects we will need */ seL4_CPtr untyped; /* TODO 2: Obtain a cap to an untyped which is large enough to contain: * - tcb * - ipc frame * - endpoint * - badged endpoint * - page table * * hint 1: determine the size of each object * (look in libs/libsel4/arch_include/x86/sel4/arch/types.h) * hint 2: an array of untyped caps, and a corresponding array of untyped sizes * can be found in the bootinfo struct * hint 3: a single untyped cap can be retyped multiple times. Each time, an appropriately sized chunk * of the object is "chipped off". For simplicity, find a cap to an untyped which is large enough * to contain all required objects. */ /* TODO 3: Using the untyped, create the required objects, storing their caps in the roottask's root cnode. * * hint 1: int seL4_Untyped_Retype(seL4_Untyped service, int type, int size_bits, seL4_CNode root, int node_index, int node_depth, int node_offset, int num_objects) * hint 2: use a depth of 32 * hint 3: use cspace_cap for the root cnode AND the cnode_index */ /* * map the frame into the vspace at ipc_buffer_vaddr. * To do this we first try to map it in to the root page directory. * If there is already a page table mapped in the appropriate slot in the * page diretory where we can insert this frame, then this will succeed. * Otherwise we first need to create a page table, and map it in to * the page`directory, before we can map the frame in. */ seL4_Word ipc_buffer_vaddr; ipc_buffer_vaddr = IPCBUF_VADDR; error = seL4_IA32_Page_Map(ipc_frame_cap, pd_cap, ipc_buffer_vaddr, seL4_AllRights, seL4_IA32_Default_VMAttributes); if (error != 0) { /* TODO 4: Retype the untyped into page table (if this was done in TODO 3, ignore this). */ error = seL4_IA32_PageTable_Map(page_table_cap, pd_cap, ipc_buffer_vaddr, seL4_IA32_Default_VMAttributes); assert(error == 0); /* then map the frame in */ error = seL4_IA32_Page_Map(ipc_frame_cap, pd_cap, ipc_buffer_vaddr, seL4_AllRights, seL4_IA32_Default_VMAttributes); assert(error == 0); } /* set the IPC buffer's virtual address in a field of the IPC buffer */ seL4_IPCBuffer *ipcbuf = (seL4_IPCBuffer*)ipc_buffer_vaddr; ipcbuf->userData = ipc_buffer_vaddr; /* TODO 5: Mint a copy of the endpoint cap into our cspace, using the badge EP_BADGE * hint: int seL4_CNode_Mint(seL4_CNode service, seL4_Word dest_index, seL4_Uint8 dest_depth, seL4_CNode src_root, seL4_Word src_index, seL4_Uint8 src_depth, seL4_CapRights rights, seL4_CapData_t badge); */ /* initialise the new TCB */ error = seL4_TCB_Configure(tcb_cap, seL4_CapNull, seL4_MaxPrio, cspace_cap, seL4_NilData, pd_cap, seL4_NilData, ipc_buffer_vaddr, ipc_frame_cap); assert(error == 0); /* give the new thread a name */ name_thread(tcb_cap, "hello-3: thread_2"); /* set start up registers for the new thread */ size_t regs_size = sizeof(seL4_UserContext) / sizeof(seL4_Word); /* check that stack is aligned correctly */ uintptr_t thread_2_stack_top = (uintptr_t)thread_2_stack + sizeof(thread_2_stack); assert(thread_2_stack_top % (sizeof(seL4_Word) * 2) == 0); /* set instruction pointer, stack pointer and gs register (used for thread local storage) */ seL4_UserContext regs = { .eip = (seL4_Word)thread_2, .esp = (seL4_Word)thread_2_stack_top, .gs = IPCBUF_GDT_SELECTOR }; /* actually write the TCB registers. */ error = seL4_TCB_WriteRegisters(tcb_cap, 0, 0, regs_size, ®s); assert(error == 0); /* start the new thread running */ error = seL4_TCB_Resume(tcb_cap); assert(error == 0); /* we are done, say hello */ printf("main: hello world\n"); /* * now send a message to the new thread, and wait for a reply */ seL4_Word msg; seL4_MessageInfo_t tag; /* set the data to send. We send it in the first message register */ tag = seL4_MessageInfo_new(0, 0, 0, 1); seL4_SetMR(0, MSG_DATA); /* send and wait for a reply */ tag = seL4_Call(badged_ep_cap, tag); /* check that we got the expected repy */ assert(seL4_MessageInfo_get_length(tag) == 1); msg = seL4_GetMR(0); assert(msg == ~MSG_DATA); printf("main: got a reply: %#x\n", msg); return 0; }
int main(void) { UNUSED int error; /* Set up logging and give us a name: useful for debugging if the thread faults */ zf_log_set_tag_prefix("hello-3:"); name_thread(seL4_CapInitThreadTCB, "hello-3"); /* get boot info */ info = seL4_GetBootInfo(); /* init simple */ simple_default_init_bootinfo(&simple, info); /* print out bootinfo and other info about simple */ simple_print(&simple); /* create an allocator */ allocman = bootstrap_use_current_simple(&simple, ALLOCATOR_STATIC_POOL_SIZE, allocator_mem_pool); ZF_LOGF_IF(allocman == NULL, "Failed to initialize alloc manager.\n" "\tMemory pool sufficiently sized?\n" "\tMemory pool pointer valid?\n"); /* create a vka (interface for interacting with the underlying allocator) */ allocman_make_vka(&vka, allocman); /* get our cspace root cnode */ seL4_CPtr cspace_cap; cspace_cap = simple_get_cnode(&simple); /* get our vspace root page directory */ seL4_CPtr pd_cap; pd_cap = simple_get_pd(&simple); /* create a new TCB */ vka_object_t tcb_object = {0}; error = vka_alloc_tcb(&vka, &tcb_object); ZF_LOGF_IFERR(error, "Failed to allocate new TCB.\n" "\tVKA given sufficient bootstrap memory?"); /* * create and map an ipc buffer: */ /* TODO 1: get a frame cap for the ipc buffer */ /* hint: vka_alloc_frame() * int vka_alloc_frame(vka_t *vka, uint32_t size_bits, vka_object_t *result) * @param vka Pointer to vka interface. * @param size_bits Frame size: 2^size_bits * @param result Structure for the Frame object. This gets initialised. * @return 0 on success * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_1: */ vka_object_t ipc_frame_object; error = vka_alloc_frame(&vka, IPCBUF_FRAME_SIZE_BITS, &ipc_frame_object); ZF_LOGF_IFERR(error, "Failed to alloc a frame for the IPC buffer.\n" "\tThe frame size is not the number of bytes, but an exponent.\n" "\tNB: This frame is not an immediately usable, virtually mapped page.\n") /* * map the frame into the vspace at ipc_buffer_vaddr. * To do this we first try to map it in to the root page directory. * If there is already a page table mapped in the appropriate slot in the * page diretory where we can insert this frame, then this will succeed. * Otherwise we first need to create a page table, and map it in to * the page directory, before we can map the frame in. */ seL4_Word ipc_buffer_vaddr = IPCBUF_VADDR; /* TODO 2: try to map the frame the first time */ /* hint 1: seL4_ARCH_Page_Map() * The *ARCH* versions of seL4 sys calls are abstractions over the architecture provided by libsel4utils * this one is defined as: * #define seL4_ARCH_Page_Map seL4_X86_Page_Map * in: Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_2: * The signature for the underlying function is: * int seL4_X86_Page_Map(seL4_X86_Page service, seL4_X86_PageDirectory pd, seL4_Word vaddr, seL4_CapRights rights, seL4_X86_VMAttributes attr) * @param service Capability to the page to map. * @param pd Capability to the VSpace which will contain the mapping. * @param vaddr Virtual address to map the page into. * @param rights Rights for the mapping. * @param attr VM Attributes for the mapping. * @return 0 on success. * * Note: this function is generated during build. It is generated from the following definition: * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_2: * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf * * hint 2: for the rights, use seL4_AllRights * hint 3: for VM attributes use seL4_ARCH_Default_VMAttributes * Hint 4: It is normal for this function call to fail. That means there are * no page tables with free slots -- proceed to the next step where you'll * be led to allocate a new empty page table and map it into the VSpace, * before trying again. */ error = seL4_ARCH_Page_Map(ipc_frame_object.cptr, pd_cap, ipc_buffer_vaddr, seL4_AllRights, seL4_ARCH_Default_VMAttributes); if (error != 0) { /* TODO 3: create a page table */ /* hint: vka_alloc_page_table() * int vka_alloc_page_table(vka_t *vka, vka_object_t *result) * @param vka Pointer to vka interface. * @param result Structure for the PageTable object. This gets initialised. * @return 0 on success * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_3: */ vka_object_t pt_object; error = vka_alloc_page_table(&vka, &pt_object); ZF_LOGF_IFERR(error, "Failed to allocate new page table.\n"); /* TODO 4: map the page table */ /* hint 1: seL4_ARCH_PageTable_Map() * The *ARCH* versions of seL4 sys calls are abstractions over the architecture provided by libsel4utils * this one is defined as: * #define seL4_ARCH_PageTable_Map seL4_X86_PageTable_Map * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_4: * The signature for the underlying function is: * int seL4_X86_PageTable_Map(seL4_X86_PageTable service, seL4_X86_PageDirectory pd, seL4_Word vaddr, seL4_X86_VMAttributes attr) * @param service Capability to the page table to map. * @param pd Capability to the VSpace which will contain the mapping. * @param vaddr Virtual address to map the page table into. * @param rights Rights for the mapping. * @param attr VM Attributes for the mapping. * @return 0 on success. * * Note: this function is generated during build. It is generated from the following definition: * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_4: * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf * * hint 2: for VM attributes use seL4_ARCH_Default_VMAttributes */ error = seL4_ARCH_PageTable_Map(pt_object.cptr, pd_cap, ipc_buffer_vaddr, seL4_ARCH_Default_VMAttributes); ZF_LOGF_IFERR(error, "Failed to map page table into VSpace.\n" "\tWe are inserting a new page table into the top-level table.\n" "\tPass a capability to the new page table, and not for example, the IPC buffer frame vaddr.\n") /* TODO 5: then map the frame in */ /* hint 1: use seL4_ARCH_Page_Map() as above * hint 2: for the rights, use seL4_AllRights * hint 3: for VM attributes use seL4_ARCH_Default_VMAttributes */ error = seL4_ARCH_Page_Map(ipc_frame_object.cptr, pd_cap, ipc_buffer_vaddr, seL4_AllRights, seL4_ARCH_Default_VMAttributes); ZF_LOGF_IFERR(error, "Failed again to map the IPC buffer frame into the VSpace.\n" "\t(It's not supposed to fail.)\n" "\tPass a capability to the IPC buffer's physical frame.\n" "\tRevisit the first seL4_ARCH_Page_Map call above and double-check your arguments.\n"); } /* set the IPC buffer's virtual address in a field of the IPC buffer */ seL4_IPCBuffer *ipcbuf = (seL4_IPCBuffer*)ipc_buffer_vaddr; ipcbuf->userData = ipc_buffer_vaddr; /* TODO 6: create an endpoint */ /* hint: vka_alloc_endpoint() * int vka_alloc_endpoint(vka_t *vka, vka_object_t *result) * @param vka Pointer to vka interface. * @param result Structure for the Endpoint object. This gets initialised. * @return 0 on success * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_6: */ error = vka_alloc_endpoint(&vka, &ep_object); ZF_LOGF_IFERR(error, "Failed to allocate new endpoint object.\n"); /* TODO 7: make a badged copy of it in our cspace. This copy will be used to send * an IPC message to the original cap */ /* hint 1: vka_mint_object() * int vka_mint_object(vka_t *vka, vka_object_t *object, cspacepath_t *result, seL4_CapRights rights, seL4_CapData_t badge) * @param[in] vka The allocator for the cspace. * @param[in] object Target object for cap minting. * @param[out] result Allocated cspacepath. * @param[in] rights The rights for the minted cap. * @param[in] badge The badge for the minted cap. * @return 0 on success * * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_7: * * hint 2: for the rights, use seL4_AllRights * hint 3: for the badge use seL4_CapData_Badge_new() * seL4_CapData_t CONST seL4_CapData_Badge_new(seL4_Uint32 Badge) * @param[in] Badge The badge number to use * @return A CapData structure containing the desired badge info * * seL4_CapData_t is generated during build. * The type definition and generated field access functions are defined in a generated file: * build/x86/pc99/libsel4/include/sel4/types_gen.h * It is generated from the following definition: * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_7: * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf * * hint 4: for the badge use EP_BADGE */ error = vka_mint_object(&vka, &ep_object, &ep_cap_path, seL4_AllRights, seL4_CapData_Badge_new(EP_BADGE)); ZF_LOGF_IFERR(error, "Failed to mint new badged copy of IPC endpoint.\n" "\tseL4_Mint is the backend for vka_mint_object.\n" "\tseL4_Mint is simply being used here to create a badged copy of the same IPC endpoint.\n" "\tThink of a badge in this case as an IPC context cookie.\n"); /* initialise the new TCB */ error = seL4_TCB_Configure(tcb_object.cptr, seL4_CapNull, seL4_PrioProps_new(seL4_MaxPrio, seL4_MaxPrio), cspace_cap, seL4_NilData, pd_cap, seL4_NilData, ipc_buffer_vaddr, ipc_frame_object.cptr); ZF_LOGF_IFERR(error, "Failed to configure the new TCB object.\n" "\tWe're running the new thread with the root thread's CSpace.\n" "\tWe're running the new thread in the root thread's VSpace.\n"); /* give the new thread a name */ name_thread(tcb_object.cptr, "hello-3: thread_2"); /* set start up registers for the new thread */ seL4_UserContext regs = {0}; size_t regs_size = sizeof(seL4_UserContext) / sizeof(seL4_Word); /* set instruction pointer where the thread shoud start running */ sel4utils_set_instruction_pointer(®s, (seL4_Word)thread_2); /* check that stack is aligned correctly */ const int stack_alignment_requirement = sizeof(seL4_Word) * 2; uintptr_t thread_2_stack_top = (uintptr_t)thread_2_stack + sizeof(thread_2_stack); ZF_LOGF_IF(thread_2_stack_top % (stack_alignment_requirement) != 0, "Stack top isn't aligned correctly to a %dB boundary.\n" "\tDouble check to ensure you're not trampling.", stack_alignment_requirement); /* set stack pointer for the new thread. remember the stack grows down */ sel4utils_set_stack_pointer(®s, thread_2_stack_top); /* set the fs register for IPC buffer */ regs.fs = IPCBUF_GDT_SELECTOR; /* actually write the TCB registers. */ error = seL4_TCB_WriteRegisters(tcb_object.cptr, 0, 0, regs_size, ®s); ZF_LOGF_IFERR(error, "Failed to write the new thread's register set.\n" "\tDid you write the correct number of registers? See arg4.\n"); /* start the new thread running */ error = seL4_TCB_Resume(tcb_object.cptr); ZF_LOGF_IFERR(error, "Failed to start new thread.\n"); /* we are done, say hello */ printf("main: hello world\n"); /* * now send a message to the new thread, and wait for a reply */ seL4_Word msg; seL4_MessageInfo_t tag; /* TODO 8: set the data to send. We send it in the first message register */ /* hint 1: seL4_MessageInfo_new() * seL4_MessageInfo_t CONST seL4_MessageInfo_new(seL4_Uint32 label, seL4_Uint32 capsUnwrapped, seL4_Uint32 extraCaps, seL4_Uint32 length) * @param label The value of the label field * @param capsUnwrapped The value of the capsUnwrapped field * @param extraCaps The value of the extraCaps field * @param length The number of message registers to send * @return The seL4_MessageInfo_t containing the given values. * * seL4_MessageInfo_new() is generated during build. It can be found in: * build/x86/pc99/libsel4/include/sel4/types_gen.h * It is generated from the following definition: * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_8: * * hint 2: use 0 for the first 3 fields. * hint 3: send only 1 message register of data * * hint 4: seL4_SetMR() * void seL4_SetMR(int i, seL4_Word mr) * @param i The message register to write * @param mr The value of the message register * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_8: * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf * * hint 5: send MSG_DATA */ tag = seL4_MessageInfo_new(0, 0, 0, 1); seL4_SetMR(0, MSG_DATA); /* TODO 9: send and wait for a reply. */ /* hint: seL4_Call() * seL4_MessageInfo_t seL4_Call(seL4_CPtr dest, seL4_MessageInfo_t msgInfo) * @param dest The capability to be invoked. * @param msgInfo The messageinfo structure for the IPC. This specifies information about the message to send (such as the number of message registers to send). * @return A seL4_MessageInfo_t structure. This is information about the repy message. * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_9: * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf * * hint 2: seL4_MessageInfo_t is generated during build. * The type definition and generated field access functions are defined in a generated file: * build/x86/pc99/libsel4/include/sel4/types_gen.h * It is generated from the following definition: * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_9: * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf */ tag = seL4_Call(ep_cap_path.capPtr, tag); /* TODO 10: get the reply message */ /* hint: seL4_GetMR() * seL4_Word seL4_GetMR(int i) * @param i The message register to retreive * @return The message register value * Link to source: https://wiki.sel4.systems/seL4%20Tutorial%203#TODO_10: * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual-3.0.0.pdf */ msg = seL4_GetMR(0); /* check that we got the expected repy */ ZF_LOGF_IF(seL4_MessageInfo_get_length(tag) != 1, "Response data from thread_2 was not the length expected.\n" "\tHow many registers did you set with seL4_SetMR within thread_2?\n"); ZF_LOGF_IF(msg != ~MSG_DATA, "Response data from thread_2's content was not what was expected.\n"); printf("main: got a reply: %#x\n", msg); return 0; }
int serial_server_client_connect(seL4_CPtr badged_server_ep_cap, vka_t *client_vka, vspace_t *client_vspace, serial_client_context_t *conn) { seL4_Error error; int shmem_n_pages; uintptr_t shmem_tmp_vaddr; seL4_MessageInfo_t tag; cspacepath_t frame_cspath; if (badged_server_ep_cap == 0 || client_vka == NULL || client_vspace == NULL || conn == NULL) { return seL4_InvalidArgument; } memset(conn, 0, sizeof(serial_client_context_t)); shmem_n_pages = BYTES_TO_4K_PAGES(SERIAL_SERVER_SHMEM_MAX_SIZE); if (shmem_n_pages > seL4_MsgMaxExtraCaps) { ZF_LOGE(SERSERVC"connect: Currently unsupported shared memory size: " "IPC cap transfer capability is inadequate."); return seL4_RangeError; } conn->shmem = vspace_new_pages(client_vspace, seL4_AllRights, shmem_n_pages, seL4_PageBits); if (conn->shmem == NULL) { ZF_LOGE(SERSERVC"connect: Failed to alloc shmem."); return seL4_NotEnoughMemory; } assert(IS_ALIGNED((uintptr_t)conn->shmem, seL4_PageBits)); /* Look up the Frame cap behind each page in the shmem range, and marshal * all of those Frame caps to the parent. The parent will then map those * Frames into its VSpace and establish a shmem link. */ shmem_tmp_vaddr = (uintptr_t)conn->shmem; for (int i = 0; i < shmem_n_pages; i++) { vka_cspace_make_path(client_vka, vspace_get_cap(client_vspace, (void *)shmem_tmp_vaddr), &frame_cspath); seL4_SetCap(i, frame_cspath.capPtr); shmem_tmp_vaddr += BIT(seL4_PageBits); } /* Call the server asking it to establish the shmem mapping with us, and * get us connected up. */ seL4_SetMR(SSMSGREG_FUNC, FUNC_CONNECT_REQ); seL4_SetMR(SSMSGREG_CONNECT_REQ_SHMEM_SIZE, SERIAL_SERVER_SHMEM_MAX_SIZE); /* extraCaps doubles up as the number of shmem pages. */ tag = seL4_MessageInfo_new(0, 0, shmem_n_pages, SSMSGREG_CONNECT_REQ_END); tag = seL4_Call(badged_server_ep_cap, tag); /* It makes sense to verify that the message we're getting back is an * ACK response to our request message. */ if (seL4_GetMR(SSMSGREG_FUNC) != FUNC_CONNECT_ACK) { error = seL4_IllegalOperation; ZF_LOGE(SERSERVC"connect: Reply message was not a CONNECT_ACK as " "expected."); goto out; } /* When the parent replies, we check to see if it was successful, etc. */ error = seL4_MessageInfo_get_label(tag); if (error != (int)SERIAL_SERVER_NOERROR) { ZF_LOGE(SERSERVC"connect ERR %d: Failed to connect to the server.", error); if (error == (int)SERIAL_SERVER_ERROR_SHMEM_TOO_LARGE) { ZF_LOGE(SERSERVC"connect: Your requested shmem mapping size is too " "large.\n\tServer's max shmem size is %luB.", (long)seL4_GetMR(SSMSGREG_CONNECT_ACK_MAX_SHMEM_SIZE)); } goto out; } conn->shmem_size = SERIAL_SERVER_SHMEM_MAX_SIZE; vka_cspace_make_path(client_vka, badged_server_ep_cap, &conn->badged_server_ep_cspath); return seL4_NoError; out: if (conn->shmem != NULL) { vspace_unmap_pages(client_vspace, (void *)conn->shmem, shmem_n_pages, seL4_PageBits, VSPACE_FREE); } return error; }
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; }