void update_owner__rx_handler(struct intermon_binding *b, intermon_caprep_t caprep, genvaddr_t st) { errval_t err; struct intermon_state *inter_st = (struct intermon_state*)b->st; coreid_t from = inter_st->core_id; struct capref capref; struct capability cap; caprep_to_capability(&caprep, &cap); err = slot_alloc(&capref); if (err_is_fail(err)) { USER_PANIC_ERR(err, "failed to allocate slot for owner update"); } err = monitor_copy_if_exists(&cap, capref); if (err_is_ok(err)) { err = monitor_set_cap_owner(cap_root, get_cap_addr(capref), get_cap_valid_bits(capref), from); } if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { err = SYS_ERR_OK; } if (err_is_fail(err)) { USER_PANIC_ERR(err, "failed to update cap ownership"); } cap_destroy(capref); err = owner_updated(from, st); if (err_is_fail(err)) { USER_PANIC_ERR(err, "failed to send ownership update response"); } }
void find_descendants__rx_handler(struct intermon_binding *b, intermon_caprep_t caprep, genvaddr_t st) { errval_t err; struct intermon_state *inter_st = (struct intermon_state*)b->st; coreid_t from = inter_st->core_id; struct capability cap; caprep_to_capability(&caprep, &cap); bool has_descendants; err = monitor_has_descendants(&cap, &has_descendants); assert(err_is_ok(err)); struct find_descendants_result_msg_st *msg_st; msg_st = malloc(sizeof(*msg_st)); if (!msg_st) { err = LIB_ERR_MALLOC_FAIL; USER_PANIC_ERR(err, "could not alloc find_descendants_result_msg_st"); } msg_st->queue_elem.cont = find_descendants_result_send_cont; msg_st->st = st; if (err_is_ok(err)) { err = has_descendants ? SYS_ERR_OK : SYS_ERR_CAP_NOT_FOUND; } msg_st->status = err; err = capsend_target(from, (struct msg_queue_elem*)msg_st); if (err_is_fail(err)) { USER_PANIC_ERR(err, "could not enqueue find_descendants_result msg"); } }
void revoke_mark__rx(struct intermon_binding *b, intermon_caprep_t caprep, genvaddr_t st) { DEBUG_CAPOPS("%s\n", __FUNCTION__); errval_t err; struct intermon_state *inter_st = (struct intermon_state*)b->st; struct revoke_slave_st *rvk_st; err = calloce(1, sizeof(*rvk_st), &rvk_st); PANIC_IF_ERR(err, "allocating revoke slave state"); rvk_st->from = inter_st->core_id; rvk_st->st = st; caprep_to_capability(&caprep, &rvk_st->rawcap); if (!slaves_head) { assert(!slaves_tail); slaves_head = slaves_tail = rvk_st; } else { assert(slaves_tail); assert(!slaves_tail->next); slaves_tail->next = rvk_st; slaves_tail = rvk_st; } // pause any ongoing "delete stepping" as mark phases on other nodes need // to delete all foreign copies before we can delete locally owned caps delete_steps_pause(); // XXX: this invocation could create a scheduling hole that could be // problematic in RT systems and should probably be done in a loop. err = monitor_revoke_mark_relations(&rvk_st->rawcap); if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) { // found no copies or descendants of capability on this core, // do nothing. -SG DEBUG_CAPOPS("no copies on core %d\n", disp_get_core_id()); } else if (err_is_fail(err)) { USER_PANIC_ERR(err, "marking revoke"); } rvk_st->im_qn.cont = revoke_ready__send; err = capsend_target(rvk_st->from, (struct msg_queue_elem*)rvk_st); PANIC_IF_ERR(err, "enqueing revoke_ready"); }
void find_cap__rx_handler(struct intermon_binding *b, intermon_caprep_t caprep, genvaddr_t st) { errval_t err, cleanup_err; struct intermon_state *inter_st = (struct intermon_state*)b->st; coreid_t from = inter_st->core_id; struct capability cap; caprep_to_capability(&caprep, &cap); struct capref capref; err = slot_alloc(&capref); if (err_is_fail(err)) { goto send_err; } err = monitor_copy_if_exists(&cap, capref); if (err_is_fail(err)) { goto free_slot; } cleanup_err = cap_delete(capref); if (err_is_fail(cleanup_err)) { USER_PANIC_ERR(err, "failed to delete temporary cap"); } free_slot: cleanup_err = slot_free(capref); if (err_is_fail(cleanup_err)) { USER_PANIC_ERR(err, "failed to free slot for temporary cap"); } send_err: cleanup_err = find_cap_result(from, err, st); if (err_is_fail(cleanup_err)) { USER_PANIC_ERR(err, "failed to send find_cap result"); } }
/** * \brief A monitor receives request to setup a connection * with another newly booted monitor from a third monitor */ static void bind_monitor_request_scc(struct intermon_binding *b, coreid_t core_id, intermon_caprep_t caprep, chanid_t chan_id, coreid_t from_core_id) { struct intermon_ump_ipi_binding *umpb = NULL; errval_t err; /* Create the cap */ struct capability cap_raw; caprep_to_capability(&caprep, &cap_raw); if (cap_raw.type != ObjType_Frame) { err = MON_ERR_WRONG_CAP_TYPE; goto error; } struct capref frame; err = slot_alloc(&frame); if (err_is_fail(err)) { goto error; } ram_set_affinity(cap_raw.u.frame.base, cap_raw.u.frame.base + ((genpaddr_t)1 << cap_raw.u.frame.bits)); err = frame_alloc(&frame, ((genpaddr_t)1 << cap_raw.u.frame.bits), NULL); ram_set_affinity(0,0); /* err = monitor_cap_create(frame, &cap_raw, core_id); */ if (err_is_fail(err)) { goto error; } struct frame_identity frameid = { .base = 0, .bits = 0 }; err = invoke_frame_identify(frame, &frameid); assert(err == SYS_ERR_OK); printf("bind_monitor_request: URPC physical frame at 0x%llx\n", frameid.base); /* Setup the connection */ void *buf; err = vspace_map_one_frame_attr(&buf, MON_URPC_SIZE, frame, VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL); if (err_is_fail(err)) { err = err_push(err, LIB_ERR_VSPACE_MAP); goto error; } // Create remote notify cap struct capref notify_cap; err = notification_create_cap(chan_id, core_id, ¬ify_cap); assert(err == SYS_ERR_OK); // Allocate my own notification caps struct capref ep, my_notify_cap; struct lmp_endpoint *iep; int chanid; err = endpoint_create(LMP_RECV_LENGTH, &ep, &iep); assert(err_is_ok(err)); err = notification_allocate(ep, &chanid); assert(err == SYS_ERR_OK); err = notification_create_cap(chanid, my_core_id, &my_notify_cap); assert(err == SYS_ERR_OK); // setup our side of the binding umpb = malloc(sizeof(struct intermon_ump_ipi_binding)); assert(umpb != NULL); err = intermon_ump_ipi_init(umpb, get_default_waitset(), buf + MON_URPC_CHANNEL_LEN, MON_URPC_CHANNEL_LEN, buf, MON_URPC_CHANNEL_LEN, notify_cap, my_notify_cap, ep, iep); assert(err_is_ok(err)); // Identify UMP frame for tracing struct frame_identity umpid; err = invoke_frame_identify(frame, &umpid); assert(err_is_ok(err)); umpb->ump_state.chan.recvid = (uintptr_t)umpid.base; umpb->ump_state.chan.sendid = (uintptr_t)(umpid.base + MON_URPC_CHANNEL_LEN); // connect it to our request handlers err = intermon_init(&umpb->b, core_id); assert(err_is_ok(err)); /* Send reply */ reply: assert(umpb != NULL); bind_monitor_reply_scc_cont(&umpb->b, err, chanid); return; error: assert(!"Argh"); // FIXME: cleanup! goto reply; } /** * \brief The monitor that proxied the request for one monitor to * setup a connection with another monitor gets the reply */ static void bind_monitor_reply_scc(struct intermon_binding *binding, errval_t err, chanid_t chan_id, coreid_t core_id) { struct intermon_ump_ipi_binding *b = (struct intermon_ump_ipi_binding *)binding; // Create notify cap to that core struct capref notify_cap; err = notification_create_cap(chan_id, core_id, ¬ify_cap); assert(err == SYS_ERR_OK); // And assign it to the binding err = ipi_notify_set(&b->ipi_notify, notify_cap); assert(err_is_ok(err)); if (err_is_fail(err)) { // XXX DEBUG_ERR(err, "Got error in bind monitor reply"); } } /******* stack-ripped bind_monitor_proxy_scc *******/ static void bind_monitor_request_scc_handler(struct intermon_binding *b, struct intermon_msg_queue_elem *e); struct bind_monitor_request_scc_state { struct intermon_msg_queue_elem elem; struct intermon_bind_monitor_request_scc__args args; }; static void bind_monitor_request_scc_cont(struct intermon_binding *dst_binding, coreid_t src_core_id, intermon_caprep_t caprep, chanid_t chan_id, coreid_t core_id) { errval_t err; err = dst_binding->tx_vtbl. bind_monitor_request_scc(dst_binding, NOP_CONT, src_core_id, caprep, chan_id, core_id); if (err_is_fail(err)) { if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { struct bind_monitor_request_scc_state *me = malloc(sizeof(struct bind_monitor_request_scc_state)); assert(me != NULL); struct intermon_state *ist = dst_binding->st; assert(ist != NULL); me->args.core_id = src_core_id; me->args.cap = caprep; me->args.chan_id = chan_id; me->args.from_core_id = core_id; me->elem.cont = bind_monitor_request_scc_handler; err = intermon_enqueue_send(dst_binding, &ist->queue, get_default_waitset(), &me->elem.queue); assert(err_is_ok(err)); return; } DEBUG_ERR(err, "forwarding bind request failed"); } }
void retrieve_request__rx(struct intermon_binding *b, intermon_caprep_t caprep, genvaddr_t st) { errval_t err, err2; struct intermon_state *inter_st = (struct intermon_state*)b->st; struct retrieve_response_st *rst; err = calloce(1, sizeof(*rst), &rst); PANIC_IF_ERR(err, "allocating retrieve respones state"); rst->st = st; rst->from = inter_st->core_id; struct capability rawcap; caprep_to_capability(&caprep, &rawcap); struct capref cap; err = slot_alloc(&cap); GOTO_IF_ERR(err, respond_err); err = monitor_copy_if_exists(&rawcap, cap); GOTO_IF_ERR(err, free_slot); distcap_state_t state; err = dom_cnode_get_state(get_cap_domref(cap), &state); GOTO_IF_ERR(err, delete_cap); if (distcap_state_is_busy(state)) { err = MON_ERR_REMOTE_CAP_RETRY; goto delete_cap; } if (distcap_state_is_foreign(state)) { err = MON_ERR_CAP_FOREIGN; goto delete_cap; } uint8_t relations, remote_relations; err = monitor_cap_has_relations(cap, 0xFF, &relations); GOTO_IF_ERR(err, delete_cap); err = monitor_remote_relations(cap, 0, 0, &remote_relations); GOTO_IF_ERR(err, delete_cap); rst->relations = relations | remote_relations | RRELS_COPY_BIT; err = monitor_set_cap_owner(cap_root, get_cap_addr(cap), get_cap_valid_bits(cap), rst->from); delete_cap: err2 = cap_delete(cap); DEBUG_IF_ERR(err2, "while deleting temp cap for retrieve"); free_slot: err2 = slot_free(cap); DEBUG_IF_ERR(err2, "freeing temp cap slot for retrieve"); respond_err: retrieve_result__enq(err, rst); }
static void intermon_bind_ump_reply(struct intermon_binding *ib, uint64_t my_mon_id, uint64_t your_mon_id, errval_t msgerr, intermon_caprep_t caprep) { errval_t err; struct remote_conn_state *con = remote_conn_lookup(my_mon_id); if (con == NULL) { USER_PANIC_ERR(0, "unknown mon_id in UMP bind reply"); return; } uintptr_t domain_id = con->domain_id; struct monitor_binding *domain_binding = con->domain_binding; struct capref notify_cap = NULL_CAP; if (err_is_ok(msgerr)) { /* bind succeeded */ con->mon_id = your_mon_id; con->mon_binding = ib; #if 0 /* map in UMP channel state */ void *buf; err = vspace_map_one_frame_attr(&buf, 2 * (UMP_CHANNEL_SIZE + con->localchan.size * sizeof(uintptr_t)), con->frame, VREGION_FLAGS_READ, NULL, NULL); if (err_is_fail(err)) { USER_PANIC_ERR(err, "vspace_map_one_frame failed"); // XXX: should not be an assert, but we don't have any way to do // connection teardown here! assert(buf != NULL); } con->sharedchan = buf; con->localchan.buf = buf + 2 * UMP_CHANNEL_SIZE; // XXX: Put frame cap on a separate allocator as it is not deleted anymore struct capref frame_copy; err = slot_alloc(&frame_copy); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Failed to allocator slot from channel_alloc"); } err = cap_copy(frame_copy, con->frame); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Failed create copy of frame cap"); } err = cap_destroy(con->frame); if (err_is_fail(err)) { USER_PANIC_ERR(err, "cap_destroy_default failed"); } con->frame = frame_copy; #endif struct capability capability; caprep_to_capability(&caprep, &capability); if(capability.type != ObjType_Null) { // Get core id of sender coreid_t core_id = ((struct intermon_state *)ib->st)->core_id; // Construct the notify cap err = slot_alloc(¬ify_cap); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc"); } err = monitor_cap_create(notify_cap, &capability, core_id); if (err_is_fail(err)) { USER_PANIC_ERR(err, "monitor_cap_create failed"); } } } else { /* bind refused */ err = cap_destroy(con->x.ump.frame); if (err_is_fail(err)) { USER_PANIC_ERR(err, "cap_destroy_default failed"); } err = remote_conn_free(my_mon_id); assert(err_is_ok(err)); } bind_ump_reply_client_cont(domain_binding, my_mon_id, domain_id, msgerr, notify_cap); }
static void intermon_bind_ump_request(struct intermon_binding *ib, iref_t iref, con_id_t your_mon_id, uint32_t channel_length_in, uint32_t channel_length_out, genpaddr_t framebase, uint8_t framebits, intermon_caprep_t caprep) { errval_t err; /* Get client's core_id */ struct intermon_state *ist = ib->st; assert(ist != NULL); coreid_t core_id = ist->core_id; /* Construct the frame capability */ struct capability frame_cap = { .type = ObjType_Frame, .rights = CAPRIGHTS_READ_WRITE, // XXX .u.frame = { .base = framebase, .bits = framebits } }; // Construct the notify cap struct capref notify_cap = NULL_CAP; struct capability capability; caprep_to_capability(&caprep, &capability); if(capability.type != ObjType_Null) { err = slot_alloc(¬ify_cap); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc"); } err = monitor_cap_create(notify_cap, &capability, core_id); if (err_is_fail(err)) { USER_PANIC_ERR(err, "monitor_cap_create failed"); } } // XXX: Put frame cap on a separate allocator as it is not deleted anymore struct capref frame; err = slot_alloc(&frame); if (err_is_fail(err)) { USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc"); } err = monitor_cap_create(frame, &frame_cap, core_id); if (err_is_fail(err)) { USER_PANIC_ERR(err, "monitor_cap_create failed"); } /* Get the server's connection */ struct monitor_binding *domain_binding = NULL; err = iref_get_binding(iref, &domain_binding); assert(err_is_ok(err)); /* Get the service id */ uintptr_t service_id = 0; err = iref_get_service_id(iref, &service_id); assert(err_is_ok(err)); /* Create a new connection state */ uintptr_t my_mon_id; struct remote_conn_state *con; err = remote_conn_alloc(&con, &my_mon_id, REMOTE_CONN_UMP); assert(err_is_ok(err)); // Set the monitor portion of it con->mon_id = your_mon_id; con->mon_binding = ib; con->x.ump.frame = frame; con->core_id = core_id; bind_ump_service_request_cont(domain_binding, service_id, my_mon_id, frame, channel_length_in, channel_length_out, notify_cap, ib, your_mon_id); }