kernel: Interaction of braces with #ifdefs was breaking the build.
[barrelfish] / kernel / dispatch.c
1 /**
2  * \file
3  * \brief Kernel management of dispatchers (implementation).
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <kernel.h>
16 #include <barrelfish_kpi/cpu.h>
17 #include <exec.h> /* XXX wait_for_interrupt, resume, execute */
18 #include <paging_kernel_arch.h>
19 #include <dispatch.h>
20 #include <kcb.h>
21 #include <wakeup.h>
22 #include <barrelfish_kpi/syscalls.h>
23 #include <barrelfish_kpi/lmp.h>
24 #include <trace/trace.h>
25 #include <trace_definitions/trace_defs.h>
26 #include <barrelfish_kpi/dispatcher_shared_target.h>
27 #include <barrelfish_kpi/cpu_arch.h>
28 #include <barrelfish_kpi/registers_arch.h>
29
30 #if defined(__x86_64__) || defined(__i386__)
31 #  include <arch/x86/apic.h>
32 #endif
33
34 #ifdef __x86_64__
35 #  include <vmkit.h>
36 #endif
37
38 #ifdef FPU_LAZY_CONTEXT_SWITCH
39 #  include <fpu.h>
40 #endif
41
42 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
43
44 /**
45  * \brief The kernel timeslice given in milliseconds.
46  */
47 int kernel_timeslice = CONFIG_TIMESLICE;
48
49 /// Counter for number of context switches
50 uint64_t context_switch_counter = 0;
51
52 /// Current execution dispatcher (when in system call or exception)
53 struct dcb *dcb_current = NULL;
54
55 /// Remembered FPU-using DCB (NULL if none)
56 struct dcb *fpu_dcb = NULL;
57
58 /**
59  * \brief Switch context to 'dcb'.
60  *
61  * This is a wrapper function to call the real, hardware-dependent
62  * context-switch function to switch to the dispatcher, pointed to by
63  * 'dcb'. It also sets 'dcb_current'.
64  *
65  * \param dcb        Pointer to dispatcher to which to switch context.
66  */
67 static inline void context_switch(struct dcb *dcb)
68 {
69 //    printf("Executing the context switch\n");
70     assert(dcb != NULL);
71     assert(dcb->vspace != 0);
72
73     // VM guests do not have a user space dispatcher
74     if (!dcb->is_vm_guest) {
75         assert(dcb->disp != 0);
76     }
77
78 #ifdef FPU_LAZY_CONTEXT_SWITCH
79     // XXX: It should be possible to merge this code fragment with the
80     // other FPU restore fragment below
81     if(fpu_dcb != NULL && !dcb->is_vm_guest) {
82         struct dispatcher_shared_generic *disp =
83             get_dispatcher_shared_generic(dcb->disp);
84
85         // Switch FPU trap on if we switch away from FPU DCB and target is enabled
86         // If target disabled, we eagerly restore the FPU
87         if(fpu_dcb != dcb && !dcb->disabled) {
88             disp->fpu_trap = 1;
89         }
90
91         // Restore FPU trap state
92         if(disp->fpu_trap) {
93             fpu_trap_on();
94         } else {
95             fpu_trap_off();
96         }
97     }
98 #endif
99
100     paging_context_switch(dcb->vspace);
101     context_switch_counter++;
102
103     if (!dcb->is_vm_guest) {
104         assert(dcb->disp_cte.cap.type == ObjType_Frame);
105
106         /* FIXME: incomplete clean-up of "thread_register" in progress here.
107          * Complain vigorously to AB if he checks this mess in
108          */
109 #if defined(__x86_64__) || defined(__k1om__)  /* Setup new LDT */
110         maybe_reload_ldt(dcb, false);
111 #else
112         struct dispatcher_shared_generic *disp =
113             get_dispatcher_shared_generic(dcb->disp);
114
115 #ifdef FPU_LAZY_CONTEXT_SWITCH
116         // Eagerly restore FPU if it was used disabled and set FPU trap accordingly
117         if(disp->fpu_used && dcb->disabled) {
118             // Context switch if FPU state is stale
119             if(fpu_dcb != dcb) {
120                 // XXX: Need to reset fpu_dcb when that DCB is deleted
121                 struct dispatcher_shared_generic *dst =
122                     get_dispatcher_shared_generic(fpu_dcb->disp);
123
124                 fpu_trap_off();
125
126                 // Store old FPU state if it was used
127                 if(fpu_dcb->disabled) {
128                     fpu_save(dispatcher_get_disabled_fpu_save_area(fpu_dcb->disp));
129                     dst->fpu_used = 1;
130                 } else {
131                     assert(!fpu_dcb->disabled);
132                     fpu_save(dispatcher_get_enabled_fpu_save_area(fpu_dcb->disp));
133                     dst->fpu_used = 2;
134                 }
135
136                 if(disp->fpu_used == 1) {
137                   fpu_restore(dispatcher_get_disabled_fpu_save_area(dcb->disp));
138                 } else {
139                   assert(disp->fpu_used == 2);
140                   fpu_restore(dispatcher_get_enabled_fpu_save_area(dcb->disp));
141                 }
142
143                 // Restore trap state once more, since we modified it
144                 if(disp->fpu_trap) {
145                     fpu_trap_on();
146                 } else {
147                     fpu_trap_off();
148                 }
149             }
150             fpu_dcb = dcb;
151         }
152 #endif /* FPU_LAZY_CONTEXT_SWITCH */
153
154         /*
155          * The name of the function is somewhat misleading. we need an unused
156          * user register that always stores the pointer to the current
157          * dispatcher. most ABIs define a register for thread-local storage,
158          * and we have been abusing that on x64 for the dispatcher pointer
159          * --arch_set_thread_ register sets this pointer.  Obviously this
160          * needs to change to support thread-local storage using a standard
161          * ABI, so we will have to figure out how to get to the dispatcher
162          * from something like a thread-local variable.  The reason that this
163          * is in the switch path and not in resume/execute is that on x86_64
164          * loading the thread register (fs) is stupidly expensive, so we avoid
165          * doing it unless we switch contexts -- presumably that could be a
166          * local optimisation in the x86_64 dispatch paths rather than the
167          * generic context_switch path/
168          */
169         arch_set_thread_register(disp->udisp);
170 #endif
171     }
172 }
173
174 #ifdef __scc__
175 struct dcb *run_next = NULL;
176 #endif
177
178 #if CONFIG_TRACE && NETWORK_STACK_BENCHMARK
179 #define TRACE_N_BM 1
180 #endif // CONFIG_TRACE && NETWORK_STACK_BENCHMARK
181
182
183 void __attribute__ ((noreturn)) dispatch(struct dcb *dcb)
184 {
185 #ifdef FPU_LAZY_CONTEXT_SWITCH
186     // Save state of FPU trap for this domain (treat it like normal context switched state)
187     if(dcb_current != NULL && !dcb_current->is_vm_guest) {
188         struct dispatcher_shared_generic *disp =
189             get_dispatcher_shared_generic(dcb_current->disp);
190         disp->fpu_trap = fpu_trap_get();
191     }
192 #endif
193
194     // XXX FIXME: Why is this null pointer check on the fast path ?
195     // If we have nothing to do we should call something other than dispatch
196     if (dcb == NULL) {
197         dcb_current = NULL;
198 #if defined(__x86_64__) || defined(__i386__) || defined(__k1om__)
199         // Can this be moved into wait_for_interrupt?
200         // Or wait_for_nonscheduling_interrupt()?
201         if (!wakeup_is_pending()) {
202             apic_mask_timer();
203         }
204 #endif
205         wait_for_interrupt();
206     }
207
208     // XXX: run_next scheduling hack
209 #ifdef __scc__
210     if(run_next != NULL) {
211         dcb = run_next;
212         run_next = NULL;
213     }
214 #endif
215
216     // Don't context switch if we are current already
217     if (dcb_current != dcb) {
218
219 #ifdef TRACE_CSWITCH
220         trace_event(TRACE_SUBSYS_KERNEL,
221                     TRACE_EVENT_KERNEL_CSWITCH,
222                     (uint32_t)(lvaddr_t)dcb & 0xFFFFFFFF);
223 #endif
224
225         context_switch(dcb);
226         dcb_current = dcb;
227     }
228
229     assert(dcb != NULL);
230
231     dispatcher_handle_t handle = dcb->disp;
232     struct dispatcher_shared_generic *disp =
233         get_dispatcher_shared_generic(handle);
234     arch_registers_state_t *disabled_area =
235         dispatcher_get_disabled_save_area(handle);
236
237     if(disp != NULL) {
238         disp->systime = kernel_now + kcb_current->kernel_off;
239     }
240     TRACE(KERNEL, SC_YIELD, 1);
241         
242     if (dcb->disabled) {
243         if (disp != NULL) {
244             debug(SUBSYS_DISPATCH, "resume %.*s at 0x%" PRIx64 "\n", DISP_NAME_LEN,
245                   disp->name, (uint64_t)registers_get_ip(disabled_area));
246             assert(dispatcher_is_disabled_ip(handle,
247                                              registers_get_ip(disabled_area)));
248         }
249
250         if(!dcb->is_vm_guest) {
251             resume(disabled_area);
252         }
253 #if defined(__x86_64__) && !defined(__k1om__)
254         else {
255             vmkit_vmenter(dcb);
256         }
257 #endif
258     } else {
259         if (disp != NULL) {
260             debug(SUBSYS_DISPATCH, "dispatch %.*s\n", DISP_NAME_LEN, disp->name);
261             assert(disp->dispatcher_run != 0);
262             disp->disabled = 1;
263         }
264         if(!dcb->is_vm_guest) {
265             execute(disp->dispatcher_run);
266     }
267 #if defined(__x86_64__) && !defined(__k1om__)
268         else {
269             vmkit_vmexec(dcb, (disp) ? disp->dispatcher_run : 0);
270         }
271 #endif
272     }
273 } // end function: dispatch
274
275 /**
276  * \brief Transfer cap from 'send' to 'ep', according to 'msg'.
277  *
278  * Reads the cap transfer spec in the LMP message 'msg' and transfers
279  * the cap from CSpace in DCB 'send' accordingly.
280  *
281  * \param ep    Endpoint capability of destination
282  * \param send  Pointer to sending DCB.
283  * \param send_cptr Address of capability in sender's cspace
284  * \param send_bits Valid bits in #send_cptr
285  *
286  * \return      Error code
287  */
288 static errval_t lmp_transfer_cap(struct capability *ep, struct dcb *send,
289                                  capaddr_t send_cptr, uint8_t send_bits,
290                                  bool give_away)
291 {
292     errval_t err;
293     /* Parameter checking */
294     assert(send_cptr != CPTR_NULL);
295     assert(send != NULL);
296     assert(ep != NULL);
297     assert(ep->type == ObjType_EndPoint);
298     struct dcb *recv = ep->u.endpoint.listener;
299     assert(recv != NULL);
300     assert(ep->u.endpoint.epoffset != 0);
301
302     /* Look up the slot receiver can receive caps in */
303     struct lmp_endpoint_kern *recv_ep
304         = (void *)((uint8_t *)recv->disp + ep->u.endpoint.epoffset);
305
306     // The cnode
307     struct capability *recv_cnode_cap;
308     err = caps_lookup_cap(&recv->cspace.cap, recv_ep->recv_cptr,
309                           recv_ep->recv_bits, &recv_cnode_cap,
310                           CAPRIGHTS_READ_WRITE);
311     if (err_is_fail(err)) {
312         return err_push(err, SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_LOOKUP);
313     }
314     // Check for cnode type
315     if (recv_cnode_cap->type != ObjType_CNode) {
316         return SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_INVALID;
317     }
318     // The slot within the cnode
319     struct cte *recv_cte;
320     recv_cte = caps_locate_slot(recv_cnode_cap->u.cnode.cnode,
321                                 recv_ep->recv_slot);
322
323     /* Look up source slot in sender */
324     struct cte *send_cte;
325     err = caps_lookup_slot(&send->cspace.cap, send_cptr, send_bits, &send_cte,
326                            CAPRIGHTS_READ);
327     if (err_is_fail(err)) {
328         return err_push(err, SYS_ERR_LMP_CAPTRANSFER_SRC_LOOKUP);
329     }
330
331     /* Is destination empty */
332     if (recv_cte->cap.type != ObjType_Null) {
333         return SYS_ERR_LMP_CAPTRANSFER_DST_SLOT_OCCUPIED;
334     }
335
336     //caps_trace(__func__, __LINE__, send_cte, "transferring");
337     //TRACE_CAP_MSG("transferring", send_cte);
338
339     /* Insert send cap into recv cap */
340     err = caps_copy_to_cte(recv_cte, send_cte, false, 0, 0);
341     assert(err_is_ok(err)); // Cannot fail after checking that slot is empty
342
343     if (give_away) {
344         err = caps_delete(send_cte);
345         if (err_is_fail(err)) {
346             printk(LOG_NOTE, "deleting source of lmp captransfer failed: %"PRIuERRV"\n", err);
347         }
348         assert(err_is_ok(err)); // A copy now exists in the recv slot, so this
349                                 // should not fail
350     }
351
352     return SYS_ERR_OK;
353 }
354
355 /**
356  * \brief Check if it would be possible to deliver LMP payload, but do not deliver it
357  *
358  * \param ep     Endpoint capability to send to
359  * \param payload_len Length (in number of words) of payload
360  */
361 errval_t lmp_can_deliver_payload(struct capability *ep,
362                                  size_t payload_len)
363 {
364     assert(ep != NULL);
365     assert(ep->type == ObjType_EndPoint);
366     struct dcb *recv = ep->u.endpoint.listener;
367     assert(recv != NULL);
368
369     /* check that receiver exists and has specified an endpoint buffer */
370     if (recv->disp == 0 || ep->u.endpoint.epoffset == 0) {
371         return SYS_ERR_LMP_NO_TARGET;
372     }
373
374     /* locate receiver's endpoint buffer */
375     struct lmp_endpoint_kern *recv_ep
376         = (void *)((uint8_t *)recv->disp + ep->u.endpoint.epoffset);
377
378     /* check delivered/consumed state */
379     uint32_t epbuflen = ep->u.endpoint.epbuflen;
380     uint32_t pos = recv_ep->delivered;
381     uint32_t consumed = recv_ep->consumed;
382     if (pos >= epbuflen || consumed >= epbuflen) {
383         return SYS_ERR_LMP_EP_STATE_INVALID;
384     }
385
386     /* compute space available in endpoint */
387     uint32_t epspace;
388     if (pos >= consumed) {
389         epspace = epbuflen - (pos - consumed);
390     } else {
391         epspace = consumed - pos;
392     }
393
394     /* Check if there's enough space for another msg.
395      * We always keep one word free, to avoid having the special case where
396      * delivered == consumed may mean the buffer is both completely full and
397      * completely empty */
398     if (epspace <= payload_len + LMP_RECV_HEADER_LENGTH) {
399         return SYS_ERR_LMP_BUF_OVERFLOW;
400     }
401
402     return SYS_ERR_OK;
403 }
404
405 /**
406  * \brief Deliver the payload of an LMP message to a dispatcher.
407  *
408  * \param ep     Endpoint capability to send to
409  * \param send   DCB of the sender. Can be NULL for kernel-originated messages
410  * \param payload     Message payload
411  * \param payload_len Length (in number of words) of payload
412  * \param captransfer True iff a cap has also been delivered
413  *
414  * \return Error code
415  */
416 errval_t lmp_deliver_payload(struct capability *ep, struct dcb *send,
417                              uintptr_t *payload, size_t payload_len,
418                              bool captransfer)
419 {
420     assert(ep != NULL);
421     assert(ep->type == ObjType_EndPoint);
422     struct dcb *recv = ep->u.endpoint.listener;
423     assert(recv != NULL);
424     assert(payload != NULL || payload_len == 0);
425
426     errval_t err;
427
428     err = lmp_can_deliver_payload(ep, payload_len);
429     if (err_is_fail(err)) {
430         return err;
431     }
432
433     /* locate receiver's endpoint buffer */
434     struct lmp_endpoint_kern *recv_ep
435         = (void *)((uint8_t *)recv->disp + ep->u.endpoint.epoffset);
436
437     /* read current pos and buflen */
438     uint32_t epbuflen = ep->u.endpoint.epbuflen;
439     uint32_t pos = recv_ep->delivered;
440
441     struct dispatcher_shared_generic *send_disp =
442         send ? get_dispatcher_shared_generic(send->disp) : NULL;
443     struct dispatcher_shared_generic *recv_disp =
444         get_dispatcher_shared_generic(recv->disp);
445     debug(SUBSYS_DISPATCH, "LMP %.*s -> %.*s\n",
446           DISP_NAME_LEN, send ? send_disp->name : "kernel",
447           DISP_NAME_LEN, recv_disp->name);
448
449     // Setup receiver's message flags
450     union lmp_recv_header recvheader = { .raw = 0 };
451     recvheader.x.flags.captransfer = captransfer;
452     recvheader.x.length = payload_len;
453
454     /* Deliver header */
455     recv_ep->buf[pos] = recvheader.raw;
456     if (++pos == epbuflen) {
457         pos = 0;
458     }
459
460     /* Transfer the msg */
461     for(int i = 0; i < payload_len; i++) {
462         recv_ep->buf[pos] = payload[i];
463         if (++pos == epbuflen) {
464             pos = 0;
465         }
466     }
467
468     // update the delivered pos
469     recv_ep->delivered = pos;
470
471     // tell the dispatcher that it has an outstanding message in one of its EPs
472     recv_disp->lmp_delivered += payload_len + LMP_RECV_HEADER_LENGTH;
473
474     // ... and give it a hint which one to look at
475     recv_disp->lmp_hint = ep->u.endpoint.epoffset;
476
477     // Make target runnable
478     make_runnable(recv);
479
480     return SYS_ERR_OK;
481 }
482
483 /**
484  * \brief Deliver an LMP message to a dispatcher.
485  *
486  * \param ep     Endpoint capability to send to
487  * \param send   DCB of the sender. Can be NULL for kernel-originated messages
488  * \param payload Buffer containing message payload
489  * \param len    Length of message payload, as number of words
490  * \param send_cptr Capability to be transferred with LMP
491  * \param send_bits Valid bits in #send_cptr
492  */
493 errval_t lmp_deliver(struct capability *ep, struct dcb *send,
494                      uintptr_t *payload, size_t len,
495                      capaddr_t send_cptr, uint8_t send_bits, bool give_away)
496 {
497     bool captransfer;
498     assert(ep != NULL);
499     assert(ep->type == ObjType_EndPoint);
500     struct dcb *recv = ep->u.endpoint.listener;
501     assert(recv != NULL);
502     assert(payload != NULL);
503
504     errval_t err;
505
506     /* Is the sender trying to send a cap? */
507     if (send_cptr != CPTR_NULL) {
508         /* Don't attempt to transfer the cap if we can't send the payload */
509         err = lmp_can_deliver_payload(ep, len);
510         if (err_is_fail(err)) {
511             return err;
512         }
513
514         err = lmp_transfer_cap(ep, send, send_cptr, send_bits, give_away);
515         if (err_is_fail(err)) {
516             return err;
517         }
518
519         captransfer = true;
520     } else {
521         captransfer = false;
522     }
523
524     /* Send msg */
525     err = lmp_deliver_payload(ep, send, payload, len, captransfer);
526     // shouldn't fail, if we delivered the cap successfully
527     assert(!(captransfer && err_is_fail(err)));
528     return err;
529 }