The initrd now works.
[akaros.git] / user / parlib / vcore_tick.c
1 /* Copyright (c) 2016 Google Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Vcore timer ticks. */
6
7 #include <parlib/vcore.h>
8 #include <parlib/uthread.h>
9 #include <parlib/assert.h>
10 #include <parlib/tsc-compat.h>
11 #include <parlib/arch/bitmask.h>
12 #include <parlib/alarm.h>
13 #include <parlib/vcore_tick.h>
14
15 /* TODO: if we use some other form of per-vcore memory, we can also have a
16  * per-vcore init function that we run before the VC spools up, removing the
17  * need to check for PREINIT. */
18
19 enum {
20         VC_TICK_PREINIT = 0,
21         VC_TICK_ENABLED = 1,
22         VC_TICK_DISABLED = 2,
23 };
24
25 struct vcore_tick {
26         int                                                     state;
27         int                                                     ctl_fd;
28         int                                                     timer_fd;
29         uint64_t                                        next_deadline;
30         uint64_t                                        period_ticks;
31         struct event_queue                      *ev_q;
32 };
33
34 static struct vcore_tick *__vc_ticks;
35
36 static void __attribute__((constructor)) vcore_tick_lib_init(void)
37 {
38         if (__in_fake_parlib())
39                 return;
40         __vc_ticks = calloc(max_vcores(), sizeof(struct vcore_tick));
41         assert(__vc_ticks);
42 }
43
44 /* Only call this from vcore context or with notifs disabled. */
45 static struct vcore_tick *get_my_tick(void)
46 {
47         return &__vc_ticks[vcore_id()];
48 }
49
50 static void vcore_tick_init(struct vcore_tick *vc_tick)
51 {
52         int ret;
53
54         ret = devalarm_get_fds(&vc_tick->ctl_fd, &vc_tick->timer_fd, 0);
55         assert(!ret);
56         /* We want an IPI and a bit set in the bitmask.  But no wakeups, in case
57          * we're offline. */
58         vc_tick->ev_q = get_eventq(EV_MBOX_BITMAP);
59         assert(vc_tick->ev_q);
60         vc_tick->ev_q->ev_flags = EVENT_IPI;
61         vc_tick->ev_q->ev_vcore = vcore_id();
62         ret = devalarm_set_evq(vc_tick->timer_fd, vc_tick->ev_q, 0);
63         assert(!ret);
64         vc_tick->state = VC_TICK_DISABLED;
65 }
66
67 static void __vcore_tick_start(struct vcore_tick *vc_tick, uint64_t from_now)
68 {
69         int ret;
70
71         ret = devalarm_set_time(vc_tick->timer_fd, read_tsc() + from_now);
72         assert(!ret);
73 }
74
75 /* Starts a timer tick for this vcore, in virtual time (time the vcore is
76  * actually online).  You can call this repeatedly, even if the timer is already
77  * on.  You also can update the period of an already-running tick. */
78 void vcore_tick_enable(uint64_t period_usec)
79 {
80         struct vcore_tick *vc_tick;
81
82         uth_disable_notifs();
83         vc_tick = get_my_tick();
84         if (vc_tick->state == VC_TICK_PREINIT)
85                 vcore_tick_init(vc_tick);
86
87         vc_tick->period_ticks = usec2tsc(period_usec);
88         if (vc_tick->state == VC_TICK_DISABLED) {
89                 vc_tick->next_deadline = vcore_account_uptime_ticks(vcore_id()) +
90                                          vc_tick->period_ticks;
91                 __vcore_tick_start(vc_tick, vc_tick->period_ticks);
92                 vc_tick->state = VC_TICK_ENABLED;
93         }
94         uth_enable_notifs();
95 }
96
97 /* Disables the timer tick.  You can call this repeatedly.  It is possible that
98  * you will still have a timer tick pending after this returns. */
99 void vcore_tick_disable(void)
100 {
101         struct vcore_tick *vc_tick;
102         int ret;
103
104         uth_disable_notifs();
105         vc_tick = get_my_tick();
106         if (vc_tick->state == VC_TICK_PREINIT)
107                 vcore_tick_init(vc_tick);
108
109         if (vc_tick->state == VC_TICK_ENABLED) {
110                 ret = devalarm_disable(vc_tick->timer_fd);
111                 assert(!ret);
112                 vc_tick->state = VC_TICK_DISABLED;
113         }
114         uth_enable_notifs();
115 }
116
117 /* Polls the vcore timer tick.  Returns the number of times it has expired, 0
118  * for not yet otherwise.  Either way, it will ensure that the underlying alarm
119  * is still turned on. */
120 int vcore_tick_poll(void)
121 {
122         struct vcore_tick *vc_tick;
123         struct evbitmap *evbm;
124         int ret = 0;
125         uint64_t from_now, virtual_now;
126
127         uth_disable_notifs();
128         vc_tick = get_my_tick();
129         if (vc_tick->state == VC_TICK_PREINIT)
130                 vcore_tick_init(vc_tick);
131
132         evbm = &vc_tick->ev_q->ev_mbox->evbm;
133         if (!GET_BITMASK_BIT(evbm->bitmap, EV_ALARM)) {
134                 /* It might be possible that the virtual time has passed, but the alarm
135                  * hasn't arrived yet.
136                  *
137                  * We assume that if the bit is not set and the tick is enabled that
138                  * the kernel still has an alarm set for us.  It is possible for the bit
139                  * to be set more than expected (disable an alarm, but fail to cancel
140                  * the alarm before it goes off, then enable it, and then we'll have the
141                  * bit set before the alarm expired).  However, it is not possible that
142                  * the bit is clear and there is no alarm pending at this point.  This
143                  * is because the only time we clear the bit is below, and then right
144                  * after that we set an alarm. (The bit is also clear at init time, and
145                  * we start the alarm when we enable the tick).
146                  *
147                  * Anyway, the alarm should be arriving shortly.  In this case, as in
148                  * the case where the bit gets set right after we check, we missed
149                  * polling for the event.  The kernel will still __notify us, setting
150                  * notif_pending, and we'll notice the next time we attempt to leave
151                  * vcore context. */
152                 uth_enable_notifs();
153                 return 0;
154         }
155         /* Don't care about clobbering neighboring bits (non-atomic op) */
156         CLR_BITMASK_BIT(evbm->bitmap, EV_ALARM);
157         /* As mentioned above, it is possible to still have an active alarm in the
158          * kernel.  We can still set a new time for the alarm, and it will just
159          * update the kernel's awaiter.  And if that alarm has fired, then we'll
160          * just have a spurious setting of the bit.  This does not affect our return
161          * value, which is based on virtual time, not alarm resets. */
162         virtual_now = vcore_account_uptime_ticks(vcore_id());
163         /* It's possible that we've fallen multiple ticks behind virtual now.
164          * In that case, we'll just jump ahead a bit */
165         while (vc_tick->next_deadline <= virtual_now) {
166                 ret++;
167                 vc_tick->next_deadline += vc_tick->period_ticks;
168         }
169         /* There's a slight chance we miss an alarm if the period is very small.
170          * virtual_now is a little old.  If the period is so small that this is a
171          * problem and if we updated virtual now in the while loop, then we'd also
172          * get caught in the while loop forever. */
173         from_now = vc_tick->next_deadline - virtual_now;
174         __vcore_tick_start(vc_tick, from_now);
175         uth_enable_notifs();
176         return ret;
177 }