void testEP(env_t env) { UNUSED int error; cspacepath_t epb1; //badged endpoint (derived from env->aep) seL4_CapData_t badge1 = seL4_CapData_Badge_new (1); //mint a badged endpoint with badge value 1 error = vka_mint_object(&env->vka, &env->aep, &epb1, seL4_CanWrite, badge1); assert(error == 0); cspacepath_t epb2; //badged endpoint (derived from env->aep) seL4_CapData_t badge2 = seL4_CapData_Badge_new (2); //mint a badged endpoint with badge value 2 error = vka_mint_object(&env->vka, &env->aep, &epb2, seL4_CanWrite, badge2); assert(error == 0); seL4_Notify(epb1.capPtr, 0); seL4_Notify(epb2.capPtr, 0); seL4_Word senderBadge; seL4_Wait(env->aep.cptr, &senderBadge); printf("senderBadge= %d\n", senderBadge); //prints 3; the two badges 1|2 //======================================= // uint32_t label = 0xF; // uint32_t capsUnwrapped = 0; // uint32_t extraCaps = 0; // uint32_t length = 3; // seL4_MessageInfo_t tag = seL4_MessageInfo_new( // label, capsUnwrapped, extraCaps, length); // seL4_SetMR(0, 0); //0xAFF); // seL4_SetMR(1, 0); //0xBFF); // seL4_SetMR(2, 0xCFF); // seL4_SetMR(3, 0xDFF); // seL4_SetMR(4, 0xEFF); // seL4_SetMR(5, 0xFFF); // seL4_NBSend(epb1.capPtr, tag); // tag = seL4_Wait(env->aep.cptr, &senderBadge); // printf("senderBadge %d\n", senderBadge); // // // in build/x86/pc99/libsel4/include/sel4/types_gen.h // label = seL4_MessageInfo_get_label(tag); // length = seL4_MessageInfo_get_length(tag); // // printf("** label=%x \n", label); // printf("** length=%x \n", length); // printf("** seL4_GetMR0=%x \n", seL4_GetMR(0)); // printf("** seL4_GetMR1=%x \n", seL4_GetMR(1)); // printf("** seL4_GetMR2=%x \n", seL4_GetMR(2)); // printf("** seL4_GetMR3=%x \n", seL4_GetMR(3)); // printf("** seL4_GetMR4=%x \n", seL4_GetMR(4)); // printf("** seL4_GetMR4=%x \n", seL4_GetMR(5)); }
seL4_CPtr vmm_create_async_event_notification_cap(vmm_t *vmm, seL4_Word badge) { if (!(badge & BIT(27))) { ZF_LOGE("Invalid badge"); return seL4_CapNull; } // notification cap seL4_CPtr ntfn = vmm->plat_callbacks.get_async_event_notification(); // path to notification cap slot cspacepath_t ntfn_path = {}; vka_cspace_make_path(&vmm->vka, ntfn, &ntfn_path); // allocate slot to store copy cspacepath_t minted_ntfn_path = {}; vka_cspace_alloc_path(&vmm->vka, &minted_ntfn_path); // mint the notification cap seL4_CapData_t badge_data = seL4_CapData_Badge_new(badge); int error = vka_cnode_mint(&minted_ntfn_path, &ntfn_path, seL4_AllRights, badge_data); if (error != seL4_NoError) { ZF_LOGE("Failed to mint notification cap"); return seL4_CapNull; } return minted_ntfn_path.capPtr; }
/* Binds and IRQ to an endpoint */ static seL4_CPtr irq_bind(irq_t irq, seL4_CPtr notification_cap, int idx, vka_t* vka, simple_t *simple) { seL4_CPtr irq_cap, bnotification_cap; cspacepath_t irq_path, notification_path, bnotification_path; seL4_CapData_t badge; int err; /* Create an IRQ cap */ err = vka_cspace_alloc(vka, &irq_cap); if (err != 0) { ZF_LOGE("Failed to allocate cslot for irq\n"); return seL4_CapNull; } vka_cspace_make_path(vka, irq_cap, &irq_path); err = simple_get_IRQ_control(simple, irq, irq_path); if (err != seL4_NoError) { ZF_LOGE("Failed to get cap to irq_number %d\n", irq); vka_cspace_free(vka, irq_cap); return seL4_CapNull; } /* Badge the provided endpoint. The bit position of the badge tells us the array * index of the associated IRQ data. */ err = vka_cspace_alloc(vka, &bnotification_cap); if (err != 0) { ZF_LOGE("Failed to allocate cslot for irq\n"); vka_cspace_free(vka, irq_cap); return seL4_CapNull; } vka_cspace_make_path(vka, notification_cap, ¬ification_path); vka_cspace_make_path(vka, bnotification_cap, &bnotification_path); badge = seL4_CapData_Badge_new(BIT(idx)); err = vka_cnode_mint(&bnotification_path, ¬ification_path, seL4_AllRights, badge); if (err != seL4_NoError) { ZF_LOGE("Failed to badge IRQ notification endpoint\n"); vka_cspace_free(vka, irq_cap); vka_cspace_free(vka, bnotification_cap); return seL4_CapNull; } /* bind the IRQ cap to our badged endpoint */ err = seL4_IRQHandler_SetNotification(irq_cap, bnotification_cap); if (err != seL4_NoError) { ZF_LOGE("Failed to bind IRQ handler to notification\n"); vka_cspace_free(vka, irq_cap); vka_cspace_free(vka, bnotification_cap); return seL4_CapNull; } /* Finally ACK any pending IRQ and enable the IRQ */ seL4_IRQHandler_Ack(irq_cap); DIRQSERVER("Registered IRQ %d with badge 0x%lx\n", irq, BIT(idx)); return irq_cap; }
int serial_server_allocate_client_badged_ep(cspacepath_t dest_slot) { cspacepath_t server_ep_cspath; seL4_Word new_badge_value = serial_server_badge_value_alloc(); if (new_badge_value == SERIAL_SERVER_BADGE_VALUE_EMPTY) { return -1; } parent_ep_obj_to_cspath(&server_ep_cspath); return vka_cnode_mint(&dest_slot, &server_ep_cspath, seL4_AllRights, seL4_CapData_Badge_new(new_badge_value)); }
int vm_install_service(vm_t* vm, seL4_CPtr service, int index, uint32_t b) { cspacepath_t src, dst; seL4_CapData_t badge; int err; badge = seL4_CapData_Badge_new(b); vka_cspace_make_path(vm->vka, service, &src); dst.root = vm->cspace.cptr; dst.capPtr = index; dst.capDepth = VM_CSPACE_SIZE_BITS; err = vka_cnode_mint(&dst, &src, seL4_AllRights, badge); return err; }
seL4_CPtr serial_server_parent_mint_endpoint_to_process(sel4utils_process_t *p) { if (p == NULL) { return 0; } cspacepath_t server_ep_cspath; seL4_Word new_badge_value = serial_server_badge_value_alloc(); if (new_badge_value == SERIAL_SERVER_BADGE_VALUE_EMPTY) { return -1; } parent_ep_obj_to_cspath(&server_ep_cspath); return sel4utils_mint_cap_to_process(p, server_ep_cspath, seL4_AllRights, seL4_CapData_Badge_new(new_badge_value)); }
int serial_server_parent_vka_mint_endpoint(vka_t *client_vka, cspacepath_t *badged_server_ep_cspath) { if (client_vka == NULL || badged_server_ep_cspath == NULL) { return seL4_InvalidArgument; } seL4_Word new_badge_value = serial_server_badge_value_alloc(); if (new_badge_value == SERIAL_SERVER_BADGE_VALUE_EMPTY) { return -1; } /* Mint the Endpoint to a new client. */ return vka_mint_object_inter_cspace(get_serial_server()->server_vka, &get_serial_server()->server_ep_obj, client_vka, badged_server_ep_cspath, seL4_AllRights, seL4_CapData_Badge_new(new_badge_value)); }
seL4_CPtr srv_mint(int badge, seL4_CPtr ep) { assert(ep); seL4_CPtr mintEP = csalloc(); if (!mintEP) { ROS_ERROR("Could not allocate cslot to mint badge."); return 0; } int error = seL4_CNode_Mint ( REFOS_CSPACE, mintEP, REFOS_CDEPTH, REFOS_CSPACE, ep, REFOS_CDEPTH, seL4_NoRead, seL4_CapData_Badge_new(badge) ); if (error != seL4_NoError) { ROS_ERROR("Could not mint badge."); csfree(mintEP); return 0; } return mintEP; }
int vm_create(const char* name, int priority, seL4_CPtr vmm_endpoint, seL4_Word vm_badge, vka_t *vka, simple_t *simple, vspace_t *vmm_vspace, ps_io_ops_t* io_ops, vm_t* vm) { seL4_CapData_t null_cap_data = {{0}}; seL4_CapData_t cspace_root_data; cspacepath_t src, dst; int err; vm->name = name; vm->ndevices = 0; vm->onode_head = NULL; vm->entry_point = NULL; vm->vka = vka; vm->simple = simple; vm->vmm_vspace = vmm_vspace; vm->io_ops = io_ops; vm->vchan_num_cons = 0; vm->vchan_cons = NULL; /* Create a cspace */ err = vka_alloc_cnode_object(vka, VM_CSPACE_SIZE_BITS, &vm->cspace); assert(!err); vka_cspace_make_path(vka, vm->cspace.cptr, &src); cspace_root_data = seL4_CapData_Guard_new(0, 32 - VM_CSPACE_SIZE_BITS); dst.root = vm->cspace.cptr; dst.capPtr = VM_CSPACE_SLOT; dst.capDepth = VM_CSPACE_SIZE_BITS; err = vka_cnode_mint(&dst, &src, seL4_AllRights, cspace_root_data); assert(!err); /* Create a vspace */ err = vka_alloc_page_directory(vka, &vm->pd); assert(!err); err = simple_ASIDPool_assign(simple, vm->pd.cptr); assert(err == seL4_NoError); err = sel4utils_get_vspace(vmm_vspace, &vm->vm_vspace, &vm->data, vka, vm->pd.cptr, &vm_object_allocation_cb, (void*)vm); assert(!err); /* Badge the endpoint */ vka_cspace_make_path(vka, vmm_endpoint, &src); err = vka_cspace_alloc_path(vka, &dst); assert(!err); err = vka_cnode_mint(&dst, &src, seL4_AllRights, seL4_CapData_Badge_new(vm_badge)); assert(!err); /* Copy it to the cspace of the VM for fault IPC */ src = dst; dst.root = vm->cspace.cptr; dst.capPtr = VM_FAULT_EP_SLOT; dst.capDepth = VM_CSPACE_SIZE_BITS; err = vka_cnode_copy(&dst, &src, seL4_AllRights); assert(!err); /* Create TCB */ err = vka_alloc_tcb(vka, &vm->tcb); assert(!err); err = seL4_TCB_Configure(vm_get_tcb(vm), VM_FAULT_EP_SLOT, priority - 1, vm->cspace.cptr, cspace_root_data, vm->pd.cptr, null_cap_data, 0, seL4_CapNull); assert(!err); /* Create VCPU */ err = vka_alloc_vcpu(vka, &vm->vcpu); assert(!err); err = seL4_ARM_VCPU_SetTCB(vm->vcpu.cptr, vm_get_tcb(vm)); assert(!err); /* Initialise fault system */ vm->fault = fault_init(vm); assert(vm->fault); return err; }
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; }
static int test_ep_recycle(env_t env) { seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); struct { helper_thread_t thread; seL4_CPtr badged_ep; seL4_CPtr derived_badged_ep; volatile seL4_Word done; } senders[NUM_BADGED_CLIENTS]; helper_thread_t bouncer; seL4_CPtr bounce_ep; UNUSED int error; seL4_CPtr ep; /* Create the master endpoint. */ ep = vka_alloc_endpoint_leaky(&env->vka); /* Create N badged endpoints, and derive each of them. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { senders[i].badged_ep = get_free_slot(env); assert(senders[i].badged_ep != 0); senders[i].derived_badged_ep = get_free_slot(env); assert(senders[i].derived_badged_ep != 0); seL4_CapData_t cap_data; cap_data = seL4_CapData_Badge_new (i + 200); error = cnode_mint(env, ep, senders[i].badged_ep, seL4_AllRights, cap_data); assert(!error); error = cnode_copy(env, senders[i].badged_ep, senders[i].derived_badged_ep, seL4_AllRights); assert(!error); create_helper_thread(env, &senders[i].thread); set_helper_priority(&senders[i].thread, 100); senders[i].done = -1; } /* Create a bounce thread so we can get lower prio threads to run. */ bounce_ep = vka_alloc_endpoint_leaky(&env->vka); create_helper_thread(env, &bouncer); set_helper_priority(&bouncer, 0); start_helper(env, &bouncer, bouncer_func, bounce_ep, 0, 0, 0); for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { start_helper(env, &senders[i].thread, (helper_fn_t) call_func, senders[i].derived_badged_ep, i + 100, (seL4_Word) &senders[i].done, 0); } /* Let the sender threads run. */ seL4_Call(bounce_ep, tag); /* Receive a message from each endpoint and check the badge. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { seL4_Word sender_badge; seL4_MessageInfo_ptr_set_length(&tag, 1); tag = seL4_Recv(ep, &sender_badge); assert(seL4_MessageInfo_get_length(tag) == 1); assert(seL4_GetMR(0) == sender_badge - 100); seL4_SetMR(0, ~seL4_GetMR(0)); seL4_Reply(tag); } /* Let the sender threads run. */ seL4_Call(bounce_ep, tag); /* Check none of the threads have failed yet. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { assert(senders[i].done == 0); } /* Recycle each endpoint. */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { error = cnode_recycle(env, senders[i].badged_ep); assert(!error); /* Let thread run. */ seL4_Call(bounce_ep, tag); /* Check that only the intended threads have now aborted. */ for (int j = 0; j < NUM_BADGED_CLIENTS; j++) { if (j <= i) { assert(senders[j].done == 1); } else { assert(senders[j].done == 0); } } } seL4_Call(bounce_ep, tag); for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { cleanup_helper(env, &senders[i].thread); } cleanup_helper(env, &bouncer); return sel4test_get_result(); }
/* RECYCLE0001 only tests if a thread gets its IPC canceled. The IPC * can succeed even if the cap it used got deleted provided the final * capability was not recycled (thus causing an IPC cancel to happen) * This means that RECYCLE0001 will pass even if all the derived badges * are deleted, since deleting them did NOT delete the final capability * or cause a recycle so outstanding IPCs were not canceled */ static int test_ep_recycle2(env_t env) { seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 0); struct { helper_thread_t thread; seL4_CPtr sync_ep; seL4_CPtr badged_ep; seL4_CPtr derived_badged_ep; volatile seL4_Word last_status; } helpers[NUM_BADGED_CLIENTS]; seL4_CPtr ep; helper_thread_t reply_thread; UNUSED int error; /* Create the main EP we are testing */ ep = vka_alloc_endpoint_leaky(&env->vka); /* spawn a thread to keep replying to any messages on main ep */ create_helper_thread(env, &reply_thread); start_helper(env, &reply_thread, bouncer_func, ep, 0, 0, 0); /* Spawn helper threads each with their own sync ep and a badged copy of the main ep */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { helpers[i].badged_ep = get_free_slot(env); assert(helpers[i].badged_ep != 0); helpers[i].derived_badged_ep = get_free_slot(env); assert(helpers[i].derived_badged_ep != 0); helpers[i].sync_ep = vka_alloc_endpoint_leaky(&env->vka); seL4_CapData_t cap_data; cap_data = seL4_CapData_Badge_new (i + 200); error = cnode_mint(env, ep, helpers[i].badged_ep, seL4_AllRights, cap_data); assert(!error); error = cnode_copy(env, helpers[i].badged_ep, helpers[i].derived_badged_ep, seL4_AllRights); assert(!error); helpers[i].last_status = -1; create_helper_thread(env, &helpers[i].thread); start_helper(env, &helpers[i].thread, (helper_fn_t) ep_test_func, helpers[i].sync_ep, helpers[i].derived_badged_ep, (seL4_Word) &helpers[i].last_status, 0); } /* Test that every thread and endpoint is working */ for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { seL4_Call(helpers[i].sync_ep, tag); } for (int i = 0; i < NUM_BADGED_CLIENTS; i++) { test_assert(helpers[i].last_status); } /* Now start recycling endpoints and make sure the correct endpoints disappear */ for (int i = 0 ; i < NUM_BADGED_CLIENTS; i++) { /* Recycle an ep */ error = cnode_recycle(env, helpers[i].badged_ep); assert(!error); /* Now run every thread */ for (int j = 0; j < NUM_BADGED_CLIENTS; j++) { seL4_Call(helpers[j].sync_ep, tag); } for (int j = 0; j < NUM_BADGED_CLIENTS; j++) { if (j <= i) { test_assert(!helpers[j].last_status); } else { test_assert(helpers[j].last_status); } } } return sel4test_get_result(); }
/* 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; }
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 inline seL4_CPtr badge_irq_ep(seL4_CPtr ep, seL4_Word badge) { seL4_CPtr badged_cap = cspace_mint_cap(cur_cspace, cur_cspace, ep, seL4_AllRights, seL4_CapData_Badge_new(badge | IRQ_EP_BADGE)); conditional_panic(!badged_cap, "Failed to allocate badged cap"); return badged_cap; }
static void _enable_ipc(int err, seL4_Word sos_vaddr, void *cookie) { process_create_data *proc = (process_create_data *) cookie; if (err) { dprintf(6, "process_create_enable_ipc: could not pin IPC buf (%d)\n", err); _fail(err, proc); return; } // Record the faulted frame address proc->pcb->ipc_vaddr = sos_vaddr; // Store the process capability for the IPC buffer into our PCB dprintf(6, "\t\tCopying process cap...\n"); err = frame_process_cap(proc->pcb->ipc_vaddr, proc->pcb, &(proc->pcb->ipc_cap)); // Broken invariant if that failed conditional_panic(err, "Failed to obtain IPC process cap"); // Copy the fault endpoint to the user app to enable IPC dprintf(6, "\t\tMinting cap...\n"); proc->pcb->ep_cap = cspace_mint_cap(proc->pcb->cspace, cur_cspace, _sos_ipc_ep_cap, seL4_AllRights, seL4_CapData_Badge_new(proc->pcb->pid)); // Make sure fault endpoint is in the first cspace slot if (!(proc->pcb->ep_cap == 1)) { _fail(1, proc); return; } // remainder of process creation dprintf(5, "\tCreating stack frame...\n"); err = _create_stack_frame(proc->pcb); if (err) { _fail(err, proc); return; } dprintf(5, "\tCreating heap...\n"); err = _create_heap(proc->pcb); if (err) { _fail(err, proc); return; } dprintf(5, "\tCreating seL4 TCB...\n"); err = _create_tcb(proc->pcb, SOS_PROCESS_PRIORITY); if (err) { _fail(err, proc); return; } dprintf(5, "\tLoading ELF...\n"); err = _load_elf(proc->pcb, proc->pcb->app_name, proc); if (err) { _fail(err, proc); return; } dprintf(5, "\tCreating children list...\n"); proc->pcb->children = list_init(); if (proc->pcb->children == NULL) { dprintf(5, "FAILED to create list head\n"); _fail(SOS_PROCESS_OOM, proc); return; } }
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() { UNUSED int err; setup_system(); /* enable serial driver */ platsupport_serial_setup_simple(NULL, &simple, &vka); printf("\n\n>>>>>>>>>> multi-irqs <<<<<<<<<< \n\n"); simple_print(&simple); /* TODO: lots of duplicate code here ... */ chardev_t serial1; chardev_t serial2; chardev_t keyboard; struct ps_io_ops opsIO; sel4platsupport_get_io_port_ops(&opsIO.io_port_ops, &simple); ps_chardevice_t *ret; ret = ps_cdev_init(PS_SERIAL0, &opsIO, &serial1.dev); assert(ret != NULL); ret = ps_cdev_init(PS_SERIAL1, &opsIO, &serial2.dev); assert(ret != NULL); ret = ps_cdev_init(PC99_KEYBOARD_PS2, &opsIO, &keyboard.dev); assert(ret != NULL); /////////////////// /* async endpoint*/ vka_object_t aep; // create endpoint err = vka_alloc_async_endpoint(&vka, &aep); assert(err == 0); seL4_CapData_t badge1 = seL4_CapData_Badge_new (1); //mint a badged endpoint with badge value 1 err = vka_mint_object(&vka, &aep, &serial1.ep, seL4_AllRights, badge1); assert(err == 0); seL4_CapData_t badge2 = seL4_CapData_Badge_new (2); //mint a badged endpoint with badge value 2 err = vka_mint_object(&vka, &aep, &serial2.ep, seL4_AllRights, badge2); assert(err == 0); seL4_CapData_t badge3 = seL4_CapData_Badge_new (4); //mint a badged endpoint with badge value 4 err = vka_mint_object(&vka, &aep, &keyboard.ep, seL4_AllRights, badge3); assert(err == 0); /////////////////// set_devEp(&serial1); set_devEp(&serial2); set_devEp(&keyboard); for (;;) { seL4_Word sender_badge; printf("waiting:\n"); UNUSED seL4_MessageInfo_t msg = seL4_Wait(aep.cptr, &sender_badge); printf("seL4_Wait returned with badge: %d\n", sender_badge); if (sender_badge & 1) { handle_cdev_event("serial1", &serial1); } if (sender_badge & 2) { handle_cdev_event("serial2", &serial2); } if (sender_badge & 4) { handle_cdev_event("keyboard", &keyboard); } } return 0; }