static void forward_kcb_rm_request(struct monitor_blocking_binding *b, coreid_t destination, struct capref kcb) { errval_t err = SYS_ERR_OK; // can't move ourselves assert(destination != my_core_id); struct capability kcb_cap; err = monitor_cap_identify(kcb, &kcb_cap); if (err_is_fail(err)) { DEBUG_ERR(err, "monitor_cap_identify failed"); err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err); assert(err_is_ok(err)); return; } struct intermon_binding *ib; err = intermon_binding_get(destination, &ib); if (err_is_fail(err)) { DEBUG_ERR(err, "intermon_binding_get failed"); err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err); assert(err_is_ok(err)); return; } uintptr_t kcb_base = (uintptr_t )kcb_cap.u.kernelcontrolblock.kcb; // send request to other monitor // remember monitor binding to send answer struct intermon_state *ist = (struct intermon_state*)ib->st; ist->originating_client = (struct monitor_binding*)b; //XXX: HACK err = ib->tx_vtbl.forward_kcb_rm_request(ib, NOP_CONT, kcb_base); assert(err_is_ok(err)); }
// XXX: these look suspicious in combination with distops! static void forward_kcb_request(struct monitor_blocking_binding *b, coreid_t destination, struct capref kcb) { printf("%s:%s:%d: forward_kcb_request in monitor\n", __FILE__, __FUNCTION__, __LINE__); errval_t err = SYS_ERR_OK; struct capability kcb_cap; err = monitor_cap_identify(kcb, &kcb_cap); if (err_is_fail(err)) { DEBUG_ERR(err, "monitor_cap_identify failed"); err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err); assert(err_is_ok(err)); return; } if (destination == my_core_id) { uintptr_t kcb_base = (uintptr_t)kcb_cap.u.kernelcontrolblock.kcb; printf("%s:%s:%d: Invoke syscall directly, destination==my_core_id; kcb_base = 0x%"PRIxPTR"\n", __FILE__, __FUNCTION__, __LINE__, kcb_base); err = invoke_monitor_add_kcb(kcb_base); if (err_is_fail(err)) { USER_PANIC_ERR(err, "invoke_montitor_add_kcb failed."); } err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err); assert(err_is_ok(err)); return; } struct intermon_binding *ib; err = intermon_binding_get(destination, &ib); if (err_is_fail(err)) { DEBUG_ERR(err, "intermon_binding_get failed"); err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err); assert(err_is_ok(err)); return; } intermon_caprep_t kcb_rep; capability_to_caprep(&kcb_cap, &kcb_rep); ib->st = b; err = ib->tx_vtbl.give_kcb_request(ib, NOP_CONT, kcb_rep); if (err_is_fail(err)) { DEBUG_ERR(err, "give_kcb send failed"); err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err); assert(err_is_ok(err)); return; } }
static void monitor_bind_ump_reply(struct monitor_binding *dom_binding, uintptr_t my_mon_id, uintptr_t domain_id, errval_t msgerr, struct capref notify) { errval_t err; struct remote_conn_state *conn = remote_conn_lookup(my_mon_id); if (conn == NULL) { USER_PANIC("invalid mon_id in UMP bind reply"); return; } uintptr_t your_mon_id = conn->mon_id; struct intermon_binding *mon_binding = conn->mon_binding; if (err_is_ok(msgerr)) { /* Connection accepted */ conn->domain_id = domain_id; conn->domain_binding = dom_binding; } else { //error: /* Free the cap */ err = cap_destroy(conn->x.ump.frame); assert(err_is_ok(err)); err = remote_conn_free(my_mon_id); assert(err_is_ok(err)); } // Identify notify cap struct capability capability; err = monitor_cap_identify(notify, &capability); if (err_is_fail(err)) { USER_PANIC_ERR(err, "monitor_cap_identify failed, ignored"); return; } assert(capability.type == ObjType_Notify_RCK || capability.type == ObjType_Notify_IPI || capability.type == ObjType_Null); /* assert(capability.u.notify.coreid == my_core_id); */ bind_ump_reply_cont(mon_binding, your_mon_id, my_mon_id, msgerr, capability); }
static void cap_identify(struct monitor_blocking_binding *b, struct capref cap) { errval_t err, reterr; union capability_caprep_u u; reterr = monitor_cap_identify(cap, &u.cap); /* XXX: shouldn't we skip this if we're being called from the monitor? * apparently not: we make a copy of the cap on LMP to self?!?! */ err = cap_destroy(cap); if (err_is_fail(err)) { USER_PANIC_ERR(err, "cap_destroy failed"); } err = b->tx_vtbl.cap_identify_response(b, NOP_CONT, reterr, u.caprepb); if (err_is_fail(err)) { USER_PANIC_ERR(err, "reply failed"); } }
static void span_domain_request(struct monitor_binding *mb, uintptr_t domain_id, uint8_t core_id, struct capref vroot, struct capref disp) { errval_t err, err2; trace_event(TRACE_SUBSYS_MONITOR, TRACE_EVENT_MONITOR_SPAN0, core_id); struct span_state *state; uintptr_t state_id; err = span_state_alloc(&state, &state_id); if (err_is_fail(err)) { err_push(err, MON_ERR_SPAN_STATE_ALLOC); goto reply; } state->core_id = core_id; state->vroot = vroot; state->mb = mb; state->domain_id = domain_id; trace_event(TRACE_SUBSYS_MONITOR, TRACE_EVENT_MONITOR_SPAN1, core_id); /* Look up the destination monitor */ struct intermon_binding *ib; err = intermon_binding_get(core_id, &ib); if (err_is_fail(err)) { goto reply; } /* Idenfity vroot */ struct capability vroot_cap; err = monitor_cap_identify(vroot, &vroot_cap); if (err_is_fail(err)) { err_push(err, MON_ERR_CAP_IDENTIFY); goto reply; } if (vroot_cap.type != ObjType_VNode_x86_64_pml4) { /* Check type */ err = MON_ERR_WRONG_CAP_TYPE; goto reply; } /* Identify the dispatcher frame */ struct frame_identity frameid; err = invoke_frame_identify(disp, &frameid); if (err_is_fail(err)) { err_push(err, LIB_ERR_FRAME_IDENTIFY); goto reply; } err = monitor_remote_relations(disp, RRELS_COPY_BIT, RRELS_COPY_BIT, NULL); if (err_is_fail(err)) { USER_PANIC_ERR(err, "monitor_remote_relations failed"); return; } err = monitor_remote_relations(vroot, RRELS_COPY_BIT, RRELS_COPY_BIT, NULL); if (err_is_fail(err)) { USER_PANIC_ERR(err, "monitor_remote_relations failed"); return; } /* Send msg to destination monitor */ err = ib->tx_vtbl.span_domain_request(ib, NOP_CONT, state_id, vroot_cap.u.vnode_x86_64_pml4.base, frameid.base, frameid.bits); if (err_is_fail(err)) { err_push(err, MON_ERR_SEND_REMOTE_MSG); goto reply; } goto cleanup; reply: err2 = mb->tx_vtbl.span_domain_reply(mb, NOP_CONT, err, domain_id); if (err_is_fail(err2)) { // XXX: Cleanup? USER_PANIC_ERR(err2, "Failed to reply to the user domain"); } if(state_id != 0) { err2 = span_state_free(state_id); if (err_is_fail(err2)) { USER_PANIC_ERR(err2, "Failed to free span state"); } } cleanup: err2 = cap_destroy(vroot); if (err_is_fail(err2)) { USER_PANIC_ERR(err2, "Failed to destroy span_vroot cap"); } err2 = cap_destroy(disp); if (err_is_fail(err2)) { USER_PANIC_ERR(err2, "Failed to destroy disp cap"); } }
/** * \brief Notification of a newly booted monitor. * Setup our connection and request the sender to proxy * the bind request to the monitor */ static void new_monitor_notify(struct intermon_binding *b, coreid_t core_id) { errval_t err; /* Setup the connection */ ram_set_affinity(SHARED_MEM_MIN + (PERCORE_MEM_SIZE * my_core_id), SHARED_MEM_MIN + (PERCORE_MEM_SIZE * (my_core_id + 1))); struct capref frame; err = frame_alloc(&frame, MON_URPC_SIZE, NULL); if (err_is_fail(err)) { DEBUG_ERR(err, "frame_alloc failed"); return; // FIXME: cleanup } ram_set_affinity(0, 0); // Reset affinity 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)) { DEBUG_ERR(err, "vspace_map_one_frame failed"); assert(buf); // XXX } // XXX: Clear the frame (kernel can't do it for us) memset(buf, 0, MON_URPC_SIZE); // 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); // init our end of the binding and channel struct intermon_ump_ipi_binding *ump_binding = malloc(sizeof(struct intermon_ump_ipi_binding)); assert(ump_binding != NULL); err = intermon_ump_ipi_init(ump_binding, get_default_waitset(), buf, MON_URPC_CHANNEL_LEN, buf + MON_URPC_CHANNEL_LEN, MON_URPC_CHANNEL_LEN, NULL_CAP, my_notify_cap, ep, iep); assert(err_is_ok(err)); /* if (err_is_fail(err)) { */ /* cap_destroy(frame); */ /* return err_push(err, LIB_ERR_UMP_CHAN_BIND); */ /* } */ // Identify UMP frame for tracing struct frame_identity umpid = { .base = 0, .bits = 0 }; err = invoke_frame_identify(frame, &umpid); assert(err_is_ok(err)); ump_binding->ump_state.chan.recvid = (uintptr_t)umpid.base; ump_binding->ump_state.chan.sendid = (uintptr_t)(umpid.base + MON_URPC_CHANNEL_LEN); err = intermon_init(&ump_binding->b, core_id); assert(err_is_ok(err)); /* Identify the frame cap */ struct capability frame_cap; err = monitor_cap_identify(frame, &frame_cap); if (err_is_fail(err)) { DEBUG_ERR(err, "monitor_cap_identify failed"); return; // FIXME: cleanup } intermon_caprep_t caprep; capability_to_caprep(&frame_cap, &caprep); /* reply to the sending monitor to proxy request */ err = b->tx_vtbl.bind_monitor_proxy_scc(b, NOP_CONT, core_id, caprep, chanid, my_core_id); if (err_is_fail(err)) { DEBUG_ERR(err, "bind proxy request failed"); } } errval_t arch_intermon_init(struct intermon_binding *b) { b->rx_vtbl.bind_monitor_request_scc = bind_monitor_request_scc; b->rx_vtbl.bind_monitor_reply_scc = bind_monitor_reply_scc; b->rx_vtbl.bind_monitor_proxy_scc = bind_monitor_proxy_scc; b->rx_vtbl.new_monitor_notify = new_monitor_notify; return SYS_ERR_OK; }
static void monitor_bind_ump_client_request(struct monitor_binding *mb, iref_t iref, uintptr_t domain_id, struct capref frame, size_t channel_length_in, size_t channel_length_out, struct capref notify) { uint8_t core_id; uintptr_t conn_id = 0; errval_t err; struct remote_conn_state *conn = NULL; // Get the core id err = iref_get_core_id(iref, &core_id); if (err_is_fail(err)) { debug_err(__FILE__, __func__, __LINE__, err, "iref_get_core_id failed"); monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); return; } if (core_id == my_core_id) { USER_PANIC("Same-core UMP binding NYI"); } /* Identify frame */ struct frame_identity frameid; err = invoke_frame_identify(frame, &frameid); if (err_is_fail(err)) { debug_err(__FILE__, __func__, __LINE__, err, "frame_identify failed"); monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); return; } // Identify notify cap struct capability capability; err = monitor_cap_identify(notify, &capability); if (err_is_fail(err)) { USER_PANIC_ERR(err, "monitor_cap_identify failed, ignored"); return; } assert(capability.type == ObjType_Notify_RCK || capability.type == ObjType_Notify_IPI || capability.type == ObjType_Null); /* assert(capability.u.notify.coreid == my_core_id); */ /* Forward request to the corresponding monitor */ // Create local state err = remote_conn_alloc(&conn, &conn_id, REMOTE_CONN_UMP); if (err_is_fail(err)) { debug_err(__FILE__, __func__, __LINE__, err, "remote_conn_alloc failed"); monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); return; } // Track data conn->domain_id = domain_id; conn->domain_binding = mb; conn->x.ump.frame = frame; conn->core_id = core_id; // Get connection to the monitor to forward request to struct intermon_binding *intermon_binding; err = intermon_binding_get(core_id, &intermon_binding); if (err_is_fail(err)) { debug_err(__FILE__, __func__, __LINE__, err, "intermon_binding_get failed"); monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); return; } bind_ump_request_cont(intermon_binding, iref, conn_id, channel_length_in, channel_length_out, frameid, capability, mb, frame, domain_id); }