int thread_config(struct proc_tcb *thread, uint8_t priority, vaddr_t entryPoint, struct vs_vspace *vspace) { assert(thread); if (!entryPoint || !vspace) { memset(thread, 0, sizeof(struct proc_tcb)); return EINVALIDPARAM; } /* Configure the new thread struct. */ dprintf("Configuring new thread 0x%x..\n", (uint32_t) thread); memset(thread, 0, sizeof(struct proc_tcb)); thread->magic = REFOS_PROCESS_THREAD_MAGIC; thread->priority = priority; thread->entryPoint = entryPoint; thread->vspaceRef = vspace; vs_ref(vspace); /* Configure the thread object. */ int error = sel4utils_configure_thread( &procServ.vka, &procServ.vspace, &vspace->vspace, REFOS_PROCSERV_EP, priority, vspace->cspace.capPtr, vspace->cspaceGuardData, &thread->sel4utilsThread ); if (error) { ROS_ERROR("Failed to configure thread for new process, error: %d.\n", error); memset(thread, 0, sizeof(struct proc_tcb)); vs_unref(vspace); return EINVALID; } return ESUCCESS; }
/** * 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); }
/* Creates a new thread for an IRQ server */ struct irq_server_thread* irq_server_thread_new(vspace_t* vspace, vka_t* vka, seL4_CPtr cspace, seL4_Word priority, simple_t *simple, seL4_Word label, seL4_CPtr sep) { struct irq_server_thread* st; int err; /* Allocate memory for the structure */ st = (struct irq_server_thread*)malloc(sizeof(*st)); if (st == NULL) { return NULL; } st->node = irq_server_node_new(0, MASK(NIRQS_PER_NODE)); if (st->node == NULL) { free(st); return NULL; } /* Initialise structure */ st->delivery_sep = sep; st->label = label; st->next = NULL; /* Create an endpoint to listen on */ err = vka_alloc_notification(vka, &st->notification); if (err) { ZF_LOGE("Failed to allocate IRQ notification endpoint for IRQ server thread\n"); return NULL; } st->node->notification = st->notification.cptr; /* Create the IRQ thread */ err = sel4utils_configure_thread(vka, vspace, vspace, seL4_CapNull, priority, cspace, seL4_NilData, &st->thread); if (err) { ZF_LOGE("Failed to configure IRQ server thread\n"); return NULL; } /* Start the thread */ err = sel4utils_start_thread(&st->thread, (void*)_irq_thread_entry, st, NULL, 1); if (err) { ZF_LOGE("Failed to start IRQ server thread\n"); return NULL; } return st; }
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; }