Пример #1
0
/* Writes the msg to the vcpd/default mbox of the vcore.  Doesn't need to check
 * for current, or care about what the process wants. */
void post_vcore_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid)
{
	struct event_mbox *vcore_mbox;
	/* kernel address of the vcpd mbox */
	vcore_mbox = get_proc_ev_mbox(p, vcoreid);
	post_ev_msg(vcore_mbox, msg, 0);		/* no chance for a NOMSG either */
}
Пример #2
0
/* Helper: use this when sending a message to a VCPD mbox.  It just posts to the
 * ev_mbox and sets notif pending.  Note this uses a userspace address for the
 * VCPD (though not a user's pointer). */
static void post_vc_msg(struct proc *p, uint32_t vcoreid,
                        struct event_mbox *ev_mbox, struct event_msg *ev_msg,
                        int ev_flags)
{
	struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
	post_ev_msg(p, ev_mbox, ev_msg, ev_flags);
	/* Set notif pending so userspace doesn't miss the message while yielding */
	wmb(); /* Ensure ev_msg write is before notif_pending */
	/* proc_notify() also sets this, but the ev_q might not have requested an
	 * IPI, so we have to do it here too. */
	vcpd->notif_pending = TRUE;
}
Пример #3
0
/* Send an event to ev_q, based on the parameters in ev_q's flag.  We don't
 * accept null ev_qs, since the caller ought to be checking before bothering to
 * make a msg and send it to the event_q.  Vcoreid is who the kernel thinks the
 * message ought to go to (for IPIs).  Appropriate for things like
 * EV_PREEMPT_PENDING, where we tell the affected vcore.  To have the message go
 * where the kernel suggests, set EVENT_VCORE_APPRO(priate). */
void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
                uint32_t vcoreid)
{
	struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
	struct proc *old_proc = pcpui->cur_proc;	/* uncounted ref */
	struct event_mbox *ev_mbox = 0, *vcore_mbox;
	struct event_msg local_msg = {0};
	assert(p);
	if (!ev_q) {
		warn("[kernel] Null ev_q - kernel code should check before sending!");
		return;
	}
	if (!is_user_rwaddr(ev_q)) {
		/* Ought to kill them, just warn for now */
		warn("[kernel] Illegal addr for ev_q");
		return;
	}
	/* ev_q can be a user pointer (not in procdata), so we need to make sure
	 * we're in the right address space */
	if (old_proc != p) {
		/* Technically, we're storing a ref here, but our current ref on p is
		 * sufficient (so long as we don't decref below) */
		pcpui->cur_proc = p;
		lcr3(p->env_cr3);
	}
	/* Get the mbox and vcoreid */
	/* If we're going with APPRO, we use the kernel's suggested vcore's ev_mbox.
	 * vcoreid is already what the kernel suggests. */
	if (ev_q->ev_flags & EVENT_VCORE_APPRO) {
		ev_mbox = get_proc_ev_mbox(p, vcoreid);
	} else {	/* common case */
		ev_mbox = ev_q->ev_mbox;
		vcoreid = ev_q->ev_vcore;
	}
	/* Check on the style, which could affect our mbox selection.  Other styles
	 * would go here (or in similar functions we call to).  Important thing is
	 * we come out knowing which vcore to send to in the event of an IPI, and we
	 * know what mbox to post to. */
	if (ev_q->ev_flags & EVENT_ROUNDROBIN) {
		/* Pick a vcore, and if we don't have a mbox yet, pick that vcore's
		 * default mbox.  Assuming ev_vcore was the previous one used.  Note
		 * that round-robin overrides the passed-in vcoreid. */
		vcoreid = (ev_q->ev_vcore + 1) % p->procinfo->num_vcores;
		ev_q->ev_vcore = vcoreid;
		if (!ev_mbox)
			ev_mbox = get_proc_ev_mbox(p, vcoreid);
	}
	/* At this point, we ought to have the right mbox to send the msg to, and
	 * which vcore to send an IPI to (if we send one).  The mbox could be the
	 * vcore's vcpd ev_mbox. */
	if (!ev_mbox) {
		/* this is a process error */
		warn("[kernel] ought to have an mbox by now!");
		goto out;
	}
	vcore_mbox = get_proc_ev_mbox(p, vcoreid);
	/* Allows the mbox to be the right vcoreid mbox (a KVA in procdata), or any
	 * other user RW location. */
	if ((ev_mbox != vcore_mbox) && (!is_user_rwaddr(ev_mbox))) {
		/* Ought to kill them, just warn for now */
		warn("[kernel] Illegal addr for ev_mbox");
		goto out;
	}
	/* We used to support no msgs, but quit being lazy and send a msg */
	assert(msg);
	post_ev_msg(ev_mbox, msg, ev_q->ev_flags);
	/* Optional IPIs */
	if (ev_q->ev_flags & EVENT_IPI) {
		/* if the mbox we sent to isn't the default one, we need to send the
		 * vcore an ev_q indirection event */
		if ((ev_mbox != vcore_mbox) && (!uva_is_kva(p, ev_mbox, vcore_mbox))) {
			/* it is tempting to send_kernel_event(), using the ev_q for that
			 * event, but that is inappropriate here, since we are sending to a
			 * specific vcore */
			local_msg.ev_type = EV_EVENT;
			local_msg.ev_arg3 = ev_q;
			post_ev_msg(vcore_mbox, &local_msg, 0);
		}
		proc_notify(p, vcoreid);
	}
out:
	/* Return to the old address space.  We switched to p in the first place if
	 * it wasn't the same as the original current (old_proc). */
	if (old_proc != p) {
		pcpui->cur_proc = old_proc;
		if (old_proc)
			lcr3(old_proc->env_cr3);
		else
			lcr3(boot_cr3);
	}
}
Пример #4
0
/* Send an event to ev_q, based on the parameters in ev_q's flag.  We don't
 * accept null ev_qs, since the caller ought to be checking before bothering to
 * make a msg and send it to the event_q.  Vcoreid is who the kernel thinks the
 * message ought to go to (for IPIs).  Appropriate for things like
 * EV_PREEMPT_PENDING, where we tell the affected vcore.  To have the message go
 * where the kernel suggests, set EVENT_VCORE_APPRO(priate). */
void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
                uint32_t vcoreid)
{
	struct proc *old_proc;
	struct event_mbox *ev_mbox = 0;
	assert(p);
	printd("[kernel] sending msg to proc %p, ev_q %p\n", p, ev_q);
	if (!ev_q) {
		warn("[kernel] Null ev_q - kernel code should check before sending!");
		return;
	}
	if (!is_user_rwaddr(ev_q, sizeof(struct event_queue))) {
		/* Ought to kill them, just warn for now */
		printk("[kernel] Illegal addr for ev_q\n");
		return;
	}
	/* This should be caught by "future technology" that can tell when the
	 * kernel PFs on the user's behalf.  For now, we catch common userspace bugs
	 * (had this happen a few times). */
	if (!PTE_ADDR(ev_q)) {
		printk("[kernel] Bad addr %p for ev_q\n", ev_q);
		return;
	}
	/* ev_q is a user pointer, so we need to make sure we're in the right
	 * address space */
	old_proc = switch_to(p);
	/* If we're an _S, just spam vcore0, and wake up if necessary. */
	if (!__proc_is_mcp(p)) {
		spam_vcore(p, 0, msg, ev_q->ev_flags);
		wrmb();	/* don't let the notif_pending write pass the state read */
		/* using the same pattern as in spam_public (which can have multiple
		 * unblock callbacks */
		if (p->state == PROC_WAITING)
			proc_wakeup(p);
		goto out;
	}
	/* Get the vcoreid that we'll message (if appropriate).  For INDIR and
	 * SPAMMING, this is the first choice of a vcore, but other vcores might get
	 * it.  Common case is !APPRO and !ROUNDROBIN.  Note we are clobbering the
	 * vcoreid parameter. */
	if (!(ev_q->ev_flags & EVENT_VCORE_APPRO))
		vcoreid = ev_q->ev_vcore;	/* use the ev_q's vcoreid */
	/* Note that RR overwrites APPRO */
	if (ev_q->ev_flags & EVENT_ROUNDROBIN) {
		/* Pick a vcore, round-robin style.  Assuming ev_vcore was the previous
		 * one used.  Note that round-robin overrides the passed-in vcoreid.
		 * Also note this may be 'wrong' if num_vcores changes. */
		vcoreid = (ev_q->ev_vcore + 1) % p->procinfo->num_vcores;
		ev_q->ev_vcore = vcoreid;
	}
	if (!vcoreid_is_safe(vcoreid)) {
		/* Ought to kill them, just warn for now */
		printk("[kernel] Vcoreid %d unsafe! (too big?)\n", vcoreid);
		goto out;
	}
	/* If we're a SPAM_PUBLIC, they just want us to spam the message.  Note we
	 * don't care about the mbox, since it'll go to VCPD public mboxes, and
	 * we'll prefer to send it to whatever vcoreid we determined at this point
	 * (via APPRO or whatever). */
	if (ev_q->ev_flags & EVENT_SPAM_PUBLIC) {
		spam_public_msg(p, msg, vcoreid, ev_q->ev_flags & EVENT_SPAM_FLAGS);
		goto out;
	}
	/* We aren't spamming and we know the default vcore, and now we need to
	 * figure out which mbox to use.  If they provided an mbox, we'll use it.
	 * If not, we'll use a VCPD mbox (public or private, depending on the
	 * flags). */
	ev_mbox = ev_q->ev_mbox;
	if (!ev_mbox)
		ev_mbox = get_vcpd_mbox(vcoreid, ev_q->ev_flags);
	/* At this point, we ought to have the right mbox to send the msg to, and
	 * which vcore to alert (IPI/INDIR) (if applicable).  The mbox could be the
	 * vcore's vcpd ev_mbox. */
	if (!ev_mbox) {
		/* This shouldn't happen any more, this is more for sanity's sake */
		warn("[kernel] ought to have an mbox by now!");
		goto out;
	}
	/* Even if we're using an mbox in procdata (VCPD), we want a user pointer */
	if (!is_user_rwaddr(ev_mbox, sizeof(struct event_mbox))) {
		/* Ought to kill them, just warn for now */
		printk("[kernel] Illegal addr for ev_mbox\n");
		goto out;
	}
	/* We used to support no msgs, but quit being lazy and send a 'msg'.  If the
	 * ev_q is a NOMSG, we won't actually memcpy or anything, it'll just be a
	 * vehicle for sending the ev_type. */
	assert(msg);
	post_ev_msg(p, ev_mbox, msg, ev_q->ev_flags);
	wmb();	/* ensure ev_msg write is before alerting the vcore */
	/* Prod/alert a vcore with an IPI or INDIR, if desired.  INDIR will also
	 * call try_notify (IPI) later */
	if (ev_q->ev_flags & EVENT_INDIR) {
		send_indir(p, ev_q, vcoreid);
	} else {
		/* they may want an IPI despite not wanting an INDIR */
		try_notify(p, vcoreid, ev_q->ev_flags);
	}
	/* Fall through */
out:
	/* Return to the old address space. */
	switch_back(p, old_proc);
}