/** * Configure a thrd */ void thrd_configure(thrd_env_t *env, thrd_t *thread) { UNUSED int error; error = vka_alloc_endpoint(&env->vka, &thread->local_endpoint); assert(error == 0); thread->is_process = false; thread->fault_endpoint = env->endpoint; seL4_CapData_t data = seL4_CapData_Guard_new(0, seL4_WordBits - env->cspace_size_bits); error = sel4utils_configure_thread(&env->vka, &env->vspace, &env->vspace, env->endpoint, THRDS_OUR_PRIO - 1, env->cspace_root, data, &thread->thread); assert(error == 0); }
int test_allocator(env_t env) { /* Perform a bunch of allocations and frees */ vka_object_t endpoint; int error; for (int i = 0; i < MIN_EXPECTED_ALLOCATIONS; i++) { error = vka_alloc_endpoint(&env->vka, &endpoint); test_assert(error == 0); test_assert(endpoint.cptr != 0); vka_free_object(&env->vka, &endpoint); } return sel4test_get_result(); }
void create_helper_process(env_t env, helper_thread_t *thread) { UNUSED int error; error = vka_alloc_endpoint(&env->vka, &thread->local_endpoint); assert(error == 0); thread->is_process = true; sel4utils_process_config_t config = { .is_elf = false, .create_cspace = true, .one_level_cspace_size_bits = env->cspace_size_bits, .create_vspace = true, .reservations = env->regions, .num_reservations = env->num_regions, .create_fault_endpoint = false, .fault_endpoint = { .cptr = env->endpoint }, .priority = OUR_PRIO - 1, #ifndef CONFIG_KERNEL_STABLE .asid_pool = env->asid_pool, #endif }; error = sel4utils_configure_process_custom(&thread->process, &env->vka, &env->vspace, config); assert(error == 0); /* copy the elf reservations we need into the current process */ memcpy(thread->regions, env->regions, sizeof(sel4utils_elf_region_t) * env->num_regions); thread->num_regions = env->num_regions; /* clone data/code into vspace */ for (int i = 0; i < env->num_regions; i++) { error = sel4utils_bootstrap_clone_into_vspace(&env->vspace, &thread->process.vspace, thread->regions[i].reservation); assert(error == 0); } thread->thread = thread->process.thread; assert(error == 0); }
static int test_kalloc(void) { test_start("kalloc"); /* Test that malloc works and the process server can allocate from static heap properly. */ for (int repeats = 0; repeats < 100; repeats++) { int *a = kmalloc(sizeof(int) * 10240); assert(a); for (int i = 0; i < 10240; i++) a[i] = i; for (int i = 0; i < 10240; i++) test_assert(a[i] == i); kfree(a); } /* Test that kernel obj allocation works and that the VKA allocator has been bootstrapped properly. */ vka_object_t obj[100]; int error = -1; for (int repeats = 0; repeats < 100; repeats++) { for (int i = 0; i < 100; i++) { error = vka_alloc_endpoint(&procServ.vka, &obj[i]); test_assert(!error); test_assert(obj[i].cptr != 0); } for (int i = 0; i < 100; i++) { vka_free_object(&procServ.vka, &obj[i]); } for (int i = 0; i < 100; i++) { error = vka_alloc_frame(&procServ.vka, seL4_PageBits, &obj[i]); test_assert(!error); test_assert(obj[i].cptr != 0); } for (int i = 0; i < 100; i++) { vka_free_object(&procServ.vka, &obj[i]); } } return test_success(); }
/*! @brief Creates a kernel endpoint object for the given process. Creates a kernel endpoint object for the given process. Also does the book-keeping underneath so that the created objects can be destroyed when the process exits. @param pcb Handle to the process to create the object for. (no ownership) @param type The kernel endpoint object type to create for the process; sync or async. @return Handle to the created object if successful (no ownership), NULL if there was an error. (eg. ran out of heap or untyped memory). */ static seL4_CPtr proc_syscall_allocate_endpoint(struct proc_pcb *pcb, kobject_t type) { assert(pcb && pcb->magic == REFOS_PCB_MAGIC); /* Allocate the kernel object. */ vka_object_t endpoint; int error = -1; if (type == KOBJECT_ENDPOINT_SYNC) { error = vka_alloc_endpoint(&procServ.vka, &endpoint); } else if (type == KOBJECT_ENDPOINT_ASYNC) { error = vka_alloc_async_endpoint(&procServ.vka, &endpoint); } else { assert(!"Invalid endpoint type."); } if (error || endpoint.cptr == 0) { ROS_ERROR("failed to allocate endpoint for process. Procserv out of memory.\n"); return 0; } /* Track this allocation, so it may be freed along with the process vspace. */ vs_track_obj(&pcb->vspace, endpoint); return endpoint.cptr; }
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 main(void) { UNUSED 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(); /* 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); assert(allocman); /* 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); assert(error == 0); /* * 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 * https://github.com/seL4/libsel4vka/blob/master/include/vka/object.h#L147 */ vka_object_t ipc_frame_object; error = vka_alloc_frame(&vka, IPCBUF_FRAME_SIZE_BITS, &ipc_frame_object); assert(error == 0); /* * 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_IA32_Page_Map * in: https://github.com/seL4/libsel4utils/blob/master/include/sel4utils/mapping.h#L69 * The signature for the underlying function is: * int seL4_IA32_Page_Map(seL4_IA32_Page service, seL4_IA32_PageDirectory pd, seL4_Word vaddr, seL4_CapRights rights, seL4_IA32_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: * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/interfaces/sel4arch.xml#L52 * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf * * 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); 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 * https://github.com/seL4/libsel4vka/blob/master/include/vka/object.h#L178 */ vka_object_t pt_object; error = vka_alloc_page_table(&vka, &pt_object); assert(error == 0); /* 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_IA32_PageTable_Map * in: https://github.com/seL4/libsel4utils/blob/master/include/sel4utils/mapping.h#L73 * The signature for the underlying function is: * int seL4_IA32_PageTable_Map(seL4_IA32_PageTable service, seL4_IA32_PageDirectory pd, seL4_Word vaddr, seL4_IA32_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: * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/interfaces/sel4arch.xml#L37 * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.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); assert(error == 0); /* 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); 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 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 * https://github.com/seL4/libsel4vka/blob/master/include/vka/object.h#L94 */ error = vka_alloc_endpoint(&vka, &ep_object); assert(error == 0); /* 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 * * https://github.com/seL4/libsel4vka/blob/master/include/vka/object_capops.h#L41 * * 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: * https://github.com/seL4/seL4/blob/master/libsel4/include/sel4/types.bf#L30 * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.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)); assert(error == 0); /* initialise the new TCB */ error = seL4_TCB_Configure(tcb_object.cptr, seL4_CapNull, seL4_MaxPrio, cspace_cap, seL4_NilData, pd_cap, seL4_NilData, ipc_buffer_vaddr, ipc_frame_object.cptr); assert(error == 0); /* 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 */ 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 stack pointer for the new thread. remember the stack grows down */ sel4utils_set_stack_pointer(®s, thread_2_stack_top); /* set the gs register for thread local storage */ regs.gs = IPCBUF_GDT_SELECTOR; /* actually write the TCB registers. */ error = seL4_TCB_WriteRegisters(tcb_object.cptr, 0, 0, regs_size, ®s); assert(error == 0); /* start the new thread running */ error = seL4_TCB_Resume(tcb_object.cptr); 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; /* 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: * https://github.com/seL4/seL4/blob/master/libsel4/include/sel4/types.bf#L35 * * 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 * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/sel4/arch/functions.h#L41 * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual.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. * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/sel4/arch/syscalls.h#L242 * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.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: * https://github.com/seL4/seL4/blob/master/libsel4/include/sel4/types.bf#L35 * You can find out more about it in the API manual: http://sel4.systems/Info/Docs/seL4-manual.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 * https://github.com/seL4/seL4/blob/master/libsel4/arch_include/x86/sel4/arch/functions.h#L33 * You can find out more about message registers in the API manual: http://sel4.systems/Info/Docs/seL4-manual.pdf */ msg = seL4_GetMR(0); /* check that we got the expected repy */ assert(seL4_MessageInfo_get_length(tag) == 1); assert(msg == ~MSG_DATA); printf("main: got a reply: %#x\n", msg); return 0; }
seL4_Error serial_server_parent_spawn_thread(simple_t *parent_simple, vka_t *parent_vka, vspace_t *parent_vspace, uint8_t priority) { const size_t shmem_max_size = SERIAL_SERVER_SHMEM_MAX_SIZE; seL4_Error error; size_t shmem_max_n_pages; cspacepath_t parent_cspace_cspath; seL4_MessageInfo_t tag; if (parent_simple == NULL || parent_vka == NULL || parent_vspace == NULL) { return seL4_InvalidArgument; } memset(get_serial_server(), 0, sizeof(serial_server_context_t)); /* Get a CPtr to the parent's root cnode. */ shmem_max_n_pages = BYTES_TO_4K_PAGES(shmem_max_size); vka_cspace_make_path(parent_vka, 0, &parent_cspace_cspath); get_serial_server()->server_vka = parent_vka; get_serial_server()->server_vspace = parent_vspace; get_serial_server()->server_cspace = parent_cspace_cspath.root; get_serial_server()->server_simple = parent_simple; /* Allocate the Endpoint that the server will be listening on. */ error = vka_alloc_endpoint(parent_vka, &get_serial_server()->server_ep_obj); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: failed to alloc endpoint, err=%d.", error); return error; } /* And also allocate a badged copy of the Server's endpoint that the Parent * can use to send to the Server. This is used to allow the Server to report * back to the Parent on whether or not the Server successfully bound to a * platform serial driver. * * This badged endpoint will be reused by the library as the Parent's badged * Endpoint cap, if the Parent itself ever chooses to connect() to the * Server later on. */ get_serial_server()->parent_badge_value = serial_server_badge_value_alloc(); if (get_serial_server()->parent_badge_value == SERIAL_SERVER_BADGE_VALUE_EMPTY) { error = seL4_NotEnoughMemory; goto out; } error = vka_mint_object(parent_vka, &get_serial_server()->server_ep_obj, &get_serial_server()->_badged_server_ep_cspath, seL4_AllRights, seL4_CapData_Badge_new(get_serial_server()->parent_badge_value)); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: Failed to mint badged Endpoint cap to " "server.\n" "\tParent cannot confirm Server thread successfully spawned."); goto out; } /* Allocate enough Cnode slots in our CSpace to enable us to receive * frame caps from our clients, sufficient to cover "shmem_max_size". * The problem here is that we're sort of forced to assume that we get * these slots contiguously. If they're not, we have a problem. * * If a client tries to send us too many frames, we respond with an error, * and indicate our shmem_max_size in the SSMSGREG_RESPONSE * message register. */ get_serial_server()->frame_cap_recv_cspaths = calloc(shmem_max_n_pages, sizeof(cspacepath_t)); if (get_serial_server()->frame_cap_recv_cspaths == NULL) { error = seL4_NotEnoughMemory; goto out; } for (size_t i = 0; i < shmem_max_n_pages; i++) { error = vka_cspace_alloc_path(parent_vka, &get_serial_server()->frame_cap_recv_cspaths[i]); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: Failed to alloc enough cnode slots " "to receive shmem frame caps equal to %d bytes.", shmem_max_size); goto out; } } error = sel4utils_configure_thread(parent_vka, parent_vspace, parent_vspace, get_serial_server()->server_ep_obj.cptr, priority, parent_cspace_cspath.root, seL4_NilData, &get_serial_server()->server_thread); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: sel4utils_configure_thread failed " "with %d.", error); goto out; } error = sel4utils_start_thread(&get_serial_server()->server_thread, &serial_server_main, NULL, NULL, 1); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: sel4utils_start_thread failed with " "%d.", error); goto out; } /* When the Server is spawned, it will reply to tell us whether or not it * successfully bound itself to the platform serial device. Block here * and wait for that reply. */ seL4_SetMR(SSMSGREG_FUNC, FUNC_SERVER_SPAWN_SYNC_REQ); tag = seL4_MessageInfo_new(0, 0, 0, SSMSGREG_SPAWN_SYNC_REQ_END); tag = seL4_Call(get_serial_server()->_badged_server_ep_cspath.capPtr, tag); /* Did all go well with the server? */ if (seL4_GetMR(SSMSGREG_FUNC) != FUNC_SERVER_SPAWN_SYNC_ACK) { ZF_LOGE(SERSERVP"spawn_thread: Server thread sync message after spawn " "was not a SYNC_ACK as expected."); error = seL4_InvalidArgument; goto out; } error = seL4_MessageInfo_get_label(tag); if (error != 0) { ZF_LOGE(SERSERVP"spawn_thread: Server thread failed to bind to the " "platform serial device."); goto out; } get_serial_server()->shmem_max_size = shmem_max_size; get_serial_server()->shmem_max_n_pages = shmem_max_n_pages; return 0; out: if (get_serial_server()->frame_cap_recv_cspaths != NULL) { for (size_t i = 0; i < shmem_max_n_pages; i++) { /* Since the array was allocated with calloc(), it was zero'd out. So * those indexes that didn't get allocated will have NULL in them. * Break early on the first index that has NULL. */ if (get_serial_server()->frame_cap_recv_cspaths[i].capPtr == 0) { break; } vka_cspace_free_path(parent_vka, get_serial_server()->frame_cap_recv_cspaths[i]); } } free(get_serial_server()->frame_cap_recv_cspaths); if (get_serial_server()->_badged_server_ep_cspath.capPtr != 0) { vka_cspace_free_path(parent_vka, get_serial_server()->_badged_server_ep_cspath); } if (get_serial_server()->parent_badge_value != SERIAL_SERVER_BADGE_VALUE_EMPTY) { serial_server_badge_value_free(get_serial_server()->parent_badge_value); } vka_free_object(parent_vka, &get_serial_server()->server_ep_obj); return error; }
static int vmm_init(void) { vka_object_t fault_ep_obj; vka_t* vka; simple_t* simple; vspace_t* vspace; int err; vka = &_vka; vspace = &_vspace; simple = &_simple; fault_ep_obj.cptr = 0; /* Camkes adds nothing to our address space, so this array is empty */ void *existing_frames[] = { NULL }; camkes_make_simple(simple); start_extra_frame_caps = simple_last_valid_cap(simple) + 1; /* Initialize allocator */ allocman = bootstrap_use_current_1level( simple_get_cnode(simple), simple_get_cnode_size_bits(simple), simple_last_valid_cap(simple) + 1 + num_extra_frame_caps, BIT(simple_get_cnode_size_bits(simple)), sizeof(allocator_mempool), allocator_mempool ); assert(allocman); err = allocman_add_simple_untypeds(allocman, simple); assert(!err); allocman_make_vka(vka, allocman); /* Initialize the vspace */ err = sel4utils_bootstrap_vspace(vspace, &_alloc_data, simple_get_init_cap(simple, seL4_CapInitThreadPD), vka, NULL, NULL, existing_frames); assert(!err); /* Initialise device support */ err = sel4platsupport_new_io_mapper(*simple, *vspace, *vka, &_io_ops.io_mapper); assert(!err); /* Initialise MUX subsystem */ err = mux_sys_init(&_io_ops, &_io_ops.mux_sys); assert(!err); /* Initialise DMA */ err = dma_dmaman_init(&_dma_morecore, NULL, &_io_ops.dma_manager); assert(!err); /* Allocate an endpoint for listening to events */ err = vka_alloc_endpoint(vka, &fault_ep_obj); assert(!err); _fault_endpoint = fault_ep_obj.cptr; /* Create an IRQ server */ err = irq_server_new(vspace, vka, simple_get_cnode(simple), IRQSERVER_PRIO, simple, fault_ep_obj.cptr, IRQ_MESSAGE_LABEL, 256, &_irq_server); assert(!err); return 0; }
int main(int argc, char **argv) { env_t *env; irquser_results_t *results; vka_object_t endpoint = {0}; static size_t object_freq[seL4_ObjectTypeCount] = { [seL4_TCBObject] = 2, [seL4_EndpointObject] = 1, #ifdef CONFIG_KERNEL_RT [seL4_SchedContextObject] = 2, [seL4_ReplyObject] = 2 #endif }; env = benchmark_get_env(argc, argv, sizeof(irquser_results_t), object_freq); benchmark_init_timer(env); results = (irquser_results_t *) env->results; if (vka_alloc_endpoint(&env->slab_vka, &endpoint) != 0) { ZF_LOGF("Failed to allocate endpoint\n"); } /* set up globals */ done_ep = endpoint.cptr; timer = &env->timer; timer_signal = env->ntfn.cptr; int error = ltimer_reset(&env->timer.ltimer); ZF_LOGF_IF(error, "Failed to start timer"); error = ltimer_set_timeout(&env->timer.ltimer, INTERRUPT_PERIOD_NS, TIMEOUT_PERIODIC); ZF_LOGF_IF(error, "Failed to configure timer"); sel4bench_init(); sel4utils_thread_t ticker, spinner; /* measurement overhead */ ccnt_t start, end; for (int i = 0; i < N_RUNS; i++) { SEL4BENCH_READ_CCNT(start); SEL4BENCH_READ_CCNT(end); results->overheads[i] = end - start; } /* create a frame for the shared time variable so we can share it between processes */ ccnt_t *local_current_time = (ccnt_t *) vspace_new_pages(&env->vspace, seL4_AllRights, 1, seL4_PageBits); if (local_current_time == NULL) { ZF_LOGF("Failed to allocate page"); } /* first run the benchmark between two threads in the current address space */ benchmark_configure_thread(env, endpoint.cptr, seL4_MaxPrio - 1, "ticker", &ticker); benchmark_configure_thread(env, endpoint.cptr, seL4_MaxPrio - 2, "spinner", &spinner); error = sel4utils_start_thread(&ticker, (sel4utils_thread_entry_fn) ticker_fn, (void *) results->thread_results, (void *) local_current_time, true); if (error) { ZF_LOGF("Failed to start ticker"); } char strings[1][WORD_STRING_SIZE]; char *spinner_argv[1]; sel4utils_create_word_args(strings, spinner_argv, 1, (seL4_Word) local_current_time); error = sel4utils_start_thread(&spinner, (sel4utils_thread_entry_fn) spinner_fn, (void *) 1, (void *) spinner_argv, true); assert(!error); benchmark_wait_children(endpoint.cptr, "child of irq-user", 1); /* stop spinner thread */ error = seL4_TCB_Suspend(spinner.tcb.cptr); assert(error == seL4_NoError); error = seL4_TCB_Suspend(ticker.tcb.cptr); assert(error == seL4_NoError); /* now run the benchmark again, but run the spinner in another address space */ /* restart ticker */ error = sel4utils_start_thread(&ticker, (sel4utils_thread_entry_fn) ticker_fn, (void *) results->process_results, (void *) local_current_time, true); assert(!error); sel4utils_process_t spinner_process; benchmark_shallow_clone_process(env, &spinner_process, seL4_MaxPrio - 2, spinner_fn, "spinner"); /* share the current time variable with the spinner process */ void *current_time_remote = vspace_share_mem(&env->vspace, &spinner_process.vspace, (void *) local_current_time, 1, seL4_PageBits, seL4_AllRights, true); assert(current_time_remote != NULL); /* start the spinner process */ sel4utils_create_word_args(strings, spinner_argv, 1, (seL4_Word) current_time_remote); error = sel4utils_spawn_process(&spinner_process, &env->slab_vka, &env->vspace, 1, spinner_argv, 1); if (error) { ZF_LOGF("Failed to start spinner process"); } benchmark_wait_children(endpoint.cptr, "child of irq-user", 1); /* done -> results are stored in shared memory so we can now return */ benchmark_finished(EXIT_SUCCESS); return 0; }