errval_t ipi_register_notification(capaddr_t ep, int chanid) { struct cte *recv; errval_t err; err = caps_lookup_slot(&dcb_current->cspace.cap, ep, 2, &recv, CAPRIGHTS_WRITE); if (err_is_fail(err)) { return err_push(err, SYS_ERR_IRQ_LOOKUP); } assert(recv != NULL); // Return w/error if cap is not an endpoint if(recv->cap.type != ObjType_EndPoint) { return SYS_ERR_IRQ_NOT_ENDPOINT; } // Return w/error if no listener on endpoint if(recv->cap.u.endpoint.listener == NULL) { return SYS_ERR_IRQ_NO_LISTENER; } if(chanid < MAX_CHANIDS) { // check that we don't overwrite someone else's handler if (endpoints[chanid].cap.type != ObjType_Null) { printf("kernel: installing new handler for IPI notification %d\n", chanid); } return caps_copy_to_cte(&endpoints[chanid], recv, false, 0, 0); } else { return SYS_ERR_IRQ_INVALID; } }
static errval_t caps_copyout_last(struct cte *target, struct cte *ret_cte) { errval_t err; // create a copy in slot specified by the caller, then delete // `next` slot so the new copy is still the last copy. err = caps_copy_to_cte(ret_cte, target, false, 0, 0); if (err_is_fail(err)) { return err; } err = cleanup_copy(target); if (err_is_fail(err)) { return err; } return SYS_ERR_OK; }
/* FIXME: lots of missing argument checks in this function */ struct sysret sys_dispatcher_setup(struct capability *to, capaddr_t cptr, int depth, capaddr_t vptr, capaddr_t dptr, bool run, capaddr_t odptr) { errval_t err = SYS_ERR_OK; assert(to->type == ObjType_Dispatcher); struct dcb *dcb = to->u.dispatcher.dcb; lpaddr_t lpaddr; /* 1. set cspace root */ if (cptr != CPTR_NULL) { struct cte *root; err = caps_lookup_slot(&dcb_current->cspace.cap, cptr, depth, &root, CAPRIGHTS_READ); if (err_is_fail(err)) { return SYSRET(err_push(err, SYS_ERR_DISP_CSPACE_ROOT)); } if (root->cap.type != ObjType_CNode) { return SYSRET(err_push(err, SYS_ERR_DISP_CSPACE_INVALID)); } err = caps_copy_to_cte(&dcb->cspace, root, false, 0, 0); if (err_is_fail(err)) { return SYSRET(err_push(err, SYS_ERR_DISP_CSPACE_ROOT)); } } /* 2. set vspace root */ if (vptr != CPTR_NULL) { struct capability *vroot; err = caps_lookup_cap(&dcb_current->cspace.cap, vptr, CPTR_BITS, &vroot, CAPRIGHTS_WRITE); if (err_is_fail(err)) { return SYSRET(err_push(err, SYS_ERR_DISP_VSPACE_ROOT)); } // Insert as dispatcher's VSpace root switch(vroot->type) { case ObjType_VNode_x86_64_pml4: dcb->vspace = (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_x86_64_pml4.base); break; #ifdef CONFIG_PAE case ObjType_VNode_x86_32_pdpt: dcb->vspace = (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_x86_32_pdpt.base); break; #else case ObjType_VNode_x86_32_pdir: dcb->vspace = (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_x86_32_pdir.base); break; #endif case ObjType_VNode_ARM_l1: dcb->vspace = (lvaddr_t)gen_phys_to_local_phys(vroot->u.vnode_arm_l1.base); break; default: return SYSRET(err_push(err, SYS_ERR_DISP_VSPACE_INVALID)); } } /* 3. set dispatcher frame pointer */ if (dptr != CPTR_NULL) { struct cte *dispcte; err = caps_lookup_slot(&dcb_current->cspace.cap, dptr, CPTR_BITS, &dispcte, CAPRIGHTS_WRITE); if (err_is_fail(err)) { return SYSRET(err_push(err, SYS_ERR_DISP_FRAME)); } struct capability *dispcap = &dispcte->cap; if (dispcap->type != ObjType_Frame) { return SYSRET(err_push(err, SYS_ERR_DISP_FRAME_INVALID)); } /* FIXME: check rights, check size */ lpaddr = gen_phys_to_local_phys(dispcap->u.frame.base); dcb->disp = local_phys_to_mem(lpaddr); // Copy the cap to dcb also err = caps_copy_to_cte(&dcb->disp_cte, dispcte, false, 0, 0); // If copy fails, something wrong in kernel assert(err_is_ok(err)); } /* 5. Make runnable if desired -- Set pointer to ipi_data */ if (run) { if (dcb->vspace == 0 || (!dcb->is_vm_guest && (dcb->disp == 0 || dcb->cspace.cap.type != ObjType_CNode))) { return SYSRET(err_push(err, SYS_ERR_DISP_NOT_RUNNABLE)); } // XXX: dispatchers run disabled the first time they start dcb->disabled = 1; //printf("DCB: %p %.*s\n", dcb, DISP_NAME_LEN, dcb->disp->name); make_runnable(dcb); } /* 6. Copy domain ID off given dispatcher */ if(odptr != CPTR_NULL) { struct capability *odisp; err = caps_lookup_cap(&dcb_current->cspace.cap, odptr, CPTR_BITS, &odisp, CAPRIGHTS_READ_WRITE); if (err_is_fail(err)) { return SYSRET(err_push(err, SYS_ERR_DISP_OCAP_LOOKUP)); } dcb->domain_id = odisp->u.dispatcher.dcb->domain_id; } /* 7. (HACK) Set current core id */ { struct dispatcher_shared_generic *disp = get_dispatcher_shared_generic(dcb->disp); disp->curr_core_id = my_core_id; } if(!dcb->is_vm_guest) { struct dispatcher_shared_generic *disp = get_dispatcher_shared_generic(dcb->disp); err = trace_new_application(disp->name, (uintptr_t) dcb); if (err == TRACE_ERR_NO_BUFFER) { // Try to use the boot buffer. trace_new_boot_application(disp->name, (uintptr_t) dcb); } } return SYSRET(SYS_ERR_OK); }