Public VCPD mboxes (XCC)
[akaros.git] / kern / src / event.c
1 /* Copyright (c) 2011 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Kernel utility functions for sending events and notifications (IPIs) to
6  * processes. */
7
8 #include <ucq.h>
9 #include <bitmask.h>
10 #include <event.h>
11 #include <atomic.h>
12 #include <process.h>
13 #include <smp.h>
14 #include <umem.h>
15 #include <stdio.h>
16 #include <assert.h>
17 #include <pmap.h>
18
19 /* Note these three helpers return the user address of the mbox, not the KVA.
20  * Load current to access this, and it will work for any process. */
21 static struct event_mbox *get_vcpd_mbox_priv(uint32_t vcoreid)
22 {
23         return &__procdata.vcore_preempt_data[vcoreid].ev_mbox_private;
24 }
25
26 static struct event_mbox *get_vcpd_mbox_pub(uint32_t vcoreid)
27 {
28         return &__procdata.vcore_preempt_data[vcoreid].ev_mbox_public;
29 }
30
31 static struct event_mbox *get_vcpd_mbox(uint32_t vcoreid, int ev_flags)
32 {
33         if (ev_flags & EVENT_VCORE_PRIVATE)
34                 return get_vcpd_mbox_priv(vcoreid);
35         else
36                 return get_vcpd_mbox_pub(vcoreid);
37 }
38
39 /* Posts a message to the mbox, subject to flags.  Feel free to send 0 for the
40  * flags if you don't want to give them the option of EVENT_NOMSG (which is what
41  * we do when sending an indirection event).  Make sure that if mbox is a user
42  * pointer, that you've checked it *and* have that processes address space
43  * loaded.  This can get called with a KVA for mbox. */
44 static void post_ev_msg(struct event_mbox *mbox, struct event_msg *msg,
45                         int ev_flags)
46 {
47         struct proc *p = current;
48         printd("[kernel] Sending event type %d to mbox %08p\n", msg->ev_type, mbox);
49         /* Sanity check */
50         assert(p);
51         /* If they just want a bit (NOMSG), just set the bit */
52         if (ev_flags & EVENT_NOMSG) {
53                 SET_BITMASK_BIT_ATOMIC(mbox->ev_bitmap, msg->ev_type);
54         } else {
55                 send_ucq_msg(&mbox->ev_msgs, p, msg);
56         }
57 }
58
59 /* Can we alert the vcore?  (Will it check its messages).  Note this checks
60  * procdata via the user pointer. */
61 static bool can_alert_vcore(uint32_t vcoreid)
62 {
63         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
64         return vcpd->can_rcv_msg;
65 }
66
67 /* Says a vcore can be alerted.  Only call this once you are sure this is true
68  * (holding the proc_lock, etc. */
69 static void set_vcore_alertable(uint32_t vcoreid)
70 {
71         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
72         vcpd->can_rcv_msg = TRUE;
73 }
74
75 /* Helper to send an indir, called from a couple places.  Note this uses a
76  * userspace address for the VCPD (though not a user's pointer). */
77 static void send_indir_to_vcore(struct event_queue *ev_q, uint32_t vcoreid)
78 {
79         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
80         struct event_msg local_msg = {0};
81         local_msg.ev_type = EV_EVENT;
82         local_msg.ev_arg3 = ev_q;
83         post_ev_msg(get_vcpd_mbox_pub(vcoreid), &local_msg, 0);
84         /* Set notif pending, so userspace doesn't miss the INDIR while yielding */
85         wmb(); /* Ensure ev_msg write is before notif_pending */
86         vcpd->notif_pending = TRUE;
87 }
88
89 /* Yet another helper, will post INDIRs and IPI a vcore, based on the needs of
90  * an ev_q.  This is called by alert_vcore(), which handles finding the vcores
91  * to alert. */
92 static void __alert_vcore(struct proc *p, struct event_queue *ev_q,
93                           uint32_t vcoreid)
94 {
95         if (ev_q->ev_flags & EVENT_INDIR)
96                 send_indir_to_vcore(ev_q, vcoreid);
97         /* Only send the IPI if it is also online (optimization).  There's a race
98          * here, but proc_notify should be able to handle it (perhaps in the
99          * future). TODO: we might need to send regardless of mapping. */
100         if ((ev_q->ev_flags & EVENT_IPI) && vcore_is_mapped(p, vcoreid))
101                 proc_notify(p, vcoreid);
102 }
103
104 /* Attempts to alert a vcore that may or may not have 'can_rcv_msg' set.  If so,
105  * we'll post the message and the message will eventually get dealt with (when
106  * the vcore runs or when it is preempte-recovered). */
107 static bool try_alert_vcore(struct proc *p, struct event_queue *ev_q,
108                             uint32_t vcoreid)
109 {
110         /* Not sure if we can or not, so check before spamming.  Technically, the
111          * only critical part is that we __alert, then check can_alert. */
112         if (can_alert_vcore(vcoreid)) {
113                 __alert_vcore(p, ev_q, vcoreid);
114                 wrmb(); /* prev write (notif_pending) must come before following reads*/
115                 if (can_alert_vcore(vcoreid))
116                         return TRUE;
117         }
118         return FALSE;
119 }
120
121 /* Helper: will try to alert (INDIR/IPI) a list member (lists of vcores).  We
122  * use this on the online and bulk_preempted vcore lists.  If this succeeds in
123  * alerting a vcore on the list, it'll return TRUE.  We need to be careful here,
124  * since we're reading a list that could be concurrently modified.  The
125  * important thing is that we can always fail if we're unsure (such as with
126  * lists being temporarily empty).  The caller will be able to deal with it via
127  * the ultimate fallback. */
128 static bool __alert_list_member(struct vcore_tailq *list, struct proc *p,
129                                 struct event_queue *ev_q)
130 {
131         struct vcore *vc, *vc_first;
132         uint32_t vcoreid;
133         int loops = 0;
134         vc = TAILQ_FIRST(list);
135         /* If the list appears empty, we'll bail out (failing) after the loop. */
136         while (vc) {
137                 vcoreid = vcore2vcoreid(p, vc);
138                 /* post the alert.  Not using the try_alert_vcore() helper since I want
139                  * something more customized for the lists. */
140                 __alert_vcore(p, ev_q, vcoreid);
141                 wrmb(); /* prev write (notif_pending) must come before following reads*/
142                 /* if they are still alertable after we sent the msg, then they'll get
143                  * it before yielding (racing with userspace yield here).  This check is
144                  * not as critical as the next one, but will allow us to alert vcores
145                  * that happen to concurrently be moved from the active to the
146                  * bulk_preempt list. */
147                 if (can_alert_vcore(vcoreid))
148                         return TRUE;
149                 /* As a backup, if they are still the first on the list, then they are
150                  * still going to get the message.  For the online list, proc_yield()
151                  * will return them to userspace (where they will get the message)
152                  * because __alert_vcore() set notif_pending.  For the BP list, they
153                  * will either be turned on later, or have a preempt message sent about
154                  * their demise.
155                  *
156                  * We race on list membership (and not exclusively 'can_rcv_msg', so
157                  * that when it fails we can get a new vcore to try (or know WHP there
158                  * are none). */
159                 vc_first = TAILQ_FIRST(list);
160                 if (vc == vc_first)
161                         return TRUE;
162                 /* At this point, the list has changed and the vcore we tried yielded,
163                  * so we try the *new* list head.  Track loops for sanity reasons. */
164                 if (loops++ > 10) {
165                         warn("Too many (%d) attempts to find a vcore, failing!", loops);
166                         return FALSE;   /* always safe to fail! */
167                 }
168                 /* Get set up for your attack run! */
169                 vc = vc_first;
170         }
171         return FALSE;
172 }
173
174 /* Helper that alerts a vcore, by IPI and/or INDIR, that it needs to check the
175  * ev_q.  Handles FALLBACK and other tricky things.  Returns which vcore was
176  * alerted.  The only caller of this is send_event(), and this makes it a little
177  * clearer/easier.
178  *
179  * One of the goals of FALLBACK (and this func) is to allow processes to yield
180  * cores without fear of losing messages (INDIR messages, btw (aka, non-vcore
181  * business)).
182  *
183  * We try the desired vcore, using 'can_rcv_msg'.  Failing that, we'll search
184  * the online and then the bulk_preempted lists.  These lists serve as a way to
185  * find likely alertable vcores.  __alert_list_member() helps us with them,
186  * failing if anything seems to go wrong.  At which point we just lock and try
187  * to deal with things.  In that scenario, we most likely would need to lock
188  * anyway to wake up the process (was WAITING).
189  *
190  * One tricky thing with sending to the bulk_preempt list is that we may want to
191  * send a message about a (bulk) preemption to someone on that list.  This works
192  * since a given vcore that was preempted will be removed from that list before
193  * we try to send_event() (in theory, there isn't code that can send that event
194  * yet).  Someone else will get the event and wake up the preempted vcore. */
195 static void alert_vcore(struct proc *p, struct event_queue *ev_q,
196                         uint32_t vcoreid)
197 {
198         struct vcore *vc;
199         /* If an alert is already pending and they don't want repeats, just return.
200          * One of the few uses of NOTHROTTLE will be for preempt_msg ev_qs.  Ex: an
201          * INDIR was already sent to the preempted vcore, then alert throttling
202          * would stop another vcore from getting the message about the original
203          * vcore. */
204         if (!(ev_q->ev_flags & EVENT_NOTHROTTLE) && (ev_q->ev_alert_pending))
205                 return;
206         /* We'll eventually get an INDIR through, so don't send any more til
207          * userspace toggles this.  Regardless of other writers to this flag, we
208          * eventually send an alert that causes userspace to turn throttling off
209          * again (before handling all of the ev_q's events).
210          *
211          * This will also squelch IPIs, since there's no reason to send the IPI if
212          * the INDIR is still un-acknowledged.  The vcore is either in vcore
213          * context, attempting to deal with the INDIR, or offline.  This statement
214          * is probably true. */
215         if (ev_q->ev_flags & EVENT_INDIR) {
216                 ev_q->ev_alert_pending = TRUE;
217                 wmb();  /* force this write to happen before any event writes */
218         }
219         /* Don't care about FALLBACK, just send and be done with it.  TODO:
220          * considering getting rid of FALLBACK as an option and making it mandatory
221          * when you want an INDIR.  Having trouble thinking of when you'd want an
222          * INDIR but not a FALLBACK. */
223         if (!(ev_q->ev_flags & EVENT_FALLBACK)) {
224                 if (ev_q->ev_flags & EVENT_INDIR)
225                         printk("[kernel] INDIR requested without FALLBACK, prob a bug.\n");
226                 __alert_vcore(p, ev_q, vcoreid);
227                 return;
228         }
229         /* If we're here, we care about FALLBACK. First, try posting to the desired
230          * vcore (so long as we don't have to send it to a vcore that will run, like
231          * we do for preempt messages). */
232         if (!(ev_q->ev_flags & EVENT_VCORE_MUST_RUN) &&
233            (try_alert_vcore(p, ev_q, vcoreid)))
234                 return;
235         /* If the process is WAITING, let's just jump to the fallback */
236         if (p->state == PROC_WAITING)
237                 goto ultimate_fallback;
238         /* If we're here, the desired vcore is unreachable, but the process is
239          * probably RUNNING_M (online_vs) or RUNNABLE_M (bulk preempted or recently
240          * woken up), so we'll need to find another vcore. */
241         if (__alert_list_member(&p->online_vcs, p, ev_q))
242                 return;
243         if (__alert_list_member(&p->bulk_preempted_vcs, p, ev_q))
244                 return;
245         /* Last chance, let's check the head of the inactives.  It might be
246          * alertable (the kernel set it earlier due to an event, or it was a
247          * bulk_preempt that didn't restart), and we can avoid grabbing the
248          * proc_lock. */
249         vc = TAILQ_FIRST(&p->inactive_vcs);
250         if (vc) {       /* might be none in rare circumstances */
251                 if (try_alert_vcore(p, ev_q, vcore2vcoreid(p, vc))) {
252                         /* Need to ensure the proc wakes up, but only if it was WAITING.
253                          * One way for this to happen is if a normal vcore was preempted
254                          * right as another vcore was yielding, and the preempted
255                          * message was sent after the last vcore yielded (which caused
256                          * us to be WAITING */
257                         if (p->state == PROC_WAITING) {
258                                 spin_lock(&p->proc_lock);
259                                 __proc_wakeup(p);       /* internally, this double-checks WAITING */
260                                 spin_unlock(&p->proc_lock);
261                         }
262                         return;
263                 }
264         }
265 ultimate_fallback:
266         /* At this point, we can't find one.  This could be due to a (hopefully
267          * rare) weird yield/request storm, or more commonly because the lists were
268          * empty and the process is simply WAITING (yielded all of its vcores and is
269          * waiting on an event).  Time for the ultimate fallback: locking.  Note
270          * that when we __alert_vcore(), there is a chance we need to mmap, which
271          * grabs the mm_lock. */
272         spin_lock(&p->proc_lock);
273         if (p->state != PROC_WAITING) {
274                 /* We need to check the online and bulk_preempt lists again, now that we are
275                  * sure no one is messing with them.  If we're WAITING, we can skip
276                  * these (or assert they are empty!). */
277                 vc = TAILQ_FIRST(&p->online_vcs);
278                 if (vc) {
279                         /* there's an online vcore, so just alert it (we know it isn't going
280                          * anywhere), and return */
281                         __alert_vcore(p, ev_q, vcore2vcoreid(p, vc));
282                         spin_unlock(&p->proc_lock);
283                         return;
284                 }
285                 vc = TAILQ_FIRST(&p->bulk_preempted_vcs);
286                 if (vc) {
287                         /* the process is bulk preempted, similar deal to above */
288                         __alert_vcore(p, ev_q, vcore2vcoreid(p, vc));
289                         spin_unlock(&p->proc_lock);
290                         return;
291                 }
292         }
293         /* At this point, we're sure all vcores are yielded, though we might not be
294          * WAITING.  Post to the first on the inactive list (which is the one that
295          * will definitely be woken up) */
296         vc = TAILQ_FIRST(&p->inactive_vcs);
297         assert(vc);
298         __alert_vcore(p, ev_q, vcore2vcoreid(p, vc));
299         /* Set the vcore's alertable flag, to short circuit our last ditch effort
300          * above */
301         set_vcore_alertable(vcore2vcoreid(p, vc));
302         /* The first event to catch the process with no online/bp vcores will need
303          * to wake it up.  (We could be RUNNABLE_M here if another event already woke
304          * us.) and we didn't get lucky with the penultimate fallback.
305          * __proc_wakeup() will check for WAITING. */
306         __proc_wakeup(p);
307         spin_unlock(&p->proc_lock);
308         return;
309 }
310
311 /* Send an event to ev_q, based on the parameters in ev_q's flag.  We don't
312  * accept null ev_qs, since the caller ought to be checking before bothering to
313  * make a msg and send it to the event_q.  Vcoreid is who the kernel thinks the
314  * message ought to go to (for IPIs).  Appropriate for things like
315  * EV_PREEMPT_PENDING, where we tell the affected vcore.  To have the message go
316  * where the kernel suggests, set EVENT_VCORE_APPRO(priate). */
317 void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
318                 uint32_t vcoreid)
319 {
320         struct proc *old_proc;
321         struct event_mbox *ev_mbox = 0;
322         assert(p);
323         printd("[kernel] sending msg to proc %08p, ev_q %08p\n", p, ev_q);
324         if (!ev_q) {
325                 warn("[kernel] Null ev_q - kernel code should check before sending!");
326                 return;
327         }
328         if (!is_user_rwaddr(ev_q, sizeof(struct event_queue))) {
329                 /* Ought to kill them, just warn for now */
330                 warn("[kernel] Illegal addr for ev_q");
331                 return;
332         }
333         /* ev_q is a user pointer, so we need to make sure we're in the right
334          * address space */
335         old_proc = switch_to(p);
336         /* Get the mbox and vcoreid */
337         /* If we're going with APPRO, we use the kernel's suggested vcore's ev_mbox.
338          * vcoreid is already what the kernel suggests. */
339         if (ev_q->ev_flags & EVENT_VCORE_APPRO) {
340                 /* flags determine if it's private (like a preempt pending) or not */
341                 ev_mbox = get_vcpd_mbox(vcoreid, ev_q->ev_flags);
342         } else {        /* common case */
343                 ev_mbox = ev_q->ev_mbox;
344                 vcoreid = ev_q->ev_vcore;
345         }
346         /* Check on the style, which could affect our mbox selection.  Other styles
347          * would go here (or in similar functions we call to).  Important thing is
348          * we come out knowing which vcore to send to in the event of an IPI/INDIR,
349          * and we know what mbox to post to. */
350         if (ev_q->ev_flags & EVENT_ROUNDROBIN) {
351                 /* Pick a vcore, and if we don't have a mbox yet, pick that vcore's
352                  * default mbox.  Assuming ev_vcore was the previous one used.  Note
353                  * that round-robin overrides the passed-in vcoreid. */
354                 vcoreid = (ev_q->ev_vcore + 1) % p->procinfo->num_vcores;
355                 ev_q->ev_vcore = vcoreid;
356                 /* Note that the style of not having a specific ev_mbox may go away.  I
357                  * can't think of legitimate uses of this for now, since things that are
358                  * RR probably are non-vcore-business, and thus inappropriate for a VCPD
359                  * ev_mbox. */
360                 if (!ev_mbox)
361                         ev_mbox = get_vcpd_mbox(vcoreid, ev_q->ev_flags);
362         }
363         /* At this point, we ought to have the right mbox to send the msg to, and
364          * which vcore to send an IPI to (if we send one).  The mbox could be the
365          * vcore's vcpd ev_mbox.  The vcoreid only matters for IPIs and INDIRs. */
366         if (!ev_mbox) {
367                 /* this is a process error */
368                 warn("[kernel] ought to have an mbox by now!");
369                 goto out;
370         }
371         /* Even if we're using an mbox in procdata (VCPD), we want a user pointer */
372         if (!is_user_rwaddr(ev_mbox, sizeof(struct event_mbox))) {
373                 /* Ought to kill them, just warn for now */
374                 warn("[kernel] Illegal addr for ev_mbox");
375                 goto out;
376         }
377         /* We used to support no msgs, but quit being lazy and send a 'msg'.  If the
378          * ev_q is a NOMSG, we won't actually memcpy or anything, it'll just be a
379          * vehicle for sending the ev_type. */
380         assert(msg);
381         post_ev_msg(ev_mbox, msg, ev_q->ev_flags);
382         wmb();  /* ensure ev_msg write is before alert_vcore() */
383         /* Help out userspace a bit by checking for a potentially confusing bug */
384         if ((ev_mbox == get_vcpd_mbox_pub(vcoreid)) &&
385             (ev_q->ev_flags & EVENT_INDIR))
386                 printk("[kernel] User-bug: ev_q has an INDIR with a VCPD ev_mbox!\n");
387         /* Prod/alert a vcore with an IPI or INDIR, if desired */
388         if ((ev_q->ev_flags & (EVENT_IPI | EVENT_INDIR)))
389                 alert_vcore(p, ev_q, vcoreid);
390         /* Fall through */
391 out:
392         /* Return to the old address space. */
393         switch_back(p, old_proc);
394 }
395
396 /* Send an event for the kernel event ev_num.  These are the "one sided" kernel
397  * initiated events, that require a lookup of the ev_q in procdata.  This is
398  * roughly equivalent to the old "proc_notify()" */
399 void send_kernel_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid)
400 {
401         uint16_t ev_num = msg->ev_type;
402         assert(ev_num < MAX_NR_EVENT);          /* events start at 0 */
403         struct event_queue *ev_q = p->procdata->kernel_evts[ev_num];
404         /* linux would put a rmb_depends() here too, i think. */
405         if (ev_q)
406                 send_event(p, ev_q, msg, vcoreid);
407 }
408
409 /* Writes the msg to the vcpd mbox of the vcore.  If you want the private mbox,
410  * send in the ev_flag EVENT_VCORE_PRIVATE.  If not, the message could
411  * be received by other vcores if the given vcore is offline/preempted/etc.
412  * Whatever other flags you pass in will get sent to post_ev_msg.  Currently,
413  * the only one that will get looked at is NO_MSG (set a bit).
414  *
415  * This needs to load current (switch_to), but doesn't need to care about what
416  * the process wants.  Note this isn't commonly used - just the monitor and
417  * sys_self_notify(). */
418 void post_vcore_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid,
419                       int ev_flags)
420 {
421         /* Need to set p as current to post the event */
422         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
423         struct proc *old_proc = switch_to(p);
424         /* *ev_mbox is the user address of the vcpd mbox */
425         post_ev_msg(get_vcpd_mbox(vcoreid, ev_flags), msg, ev_flags);
426         switch_back(p, old_proc);
427 }