monitor: remove old capability code
[barrelfish] / usr / monitor / monitor_rpc_server.c
1 /** \file
2  *  \brief Monitor's connection with the dispatchers on the same core for
3  *  blocking rpc calls.
4  */
5
6 /*
7  * Copyright (c) 2009, 2010, 2011, 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
16 #include "monitor.h"
17 #include <barrelfish/monitor_client.h>
18 #include "capops.h"
19
20 // workaround inlining bug with gcc 4.4.1 shipped with ubuntu 9.10 and 4.4.3 in Debian
21 #if defined(__i386__) && defined(__GNUC__) \
22     && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ <= 3
23 #define SAFEINLINE __attribute__((noinline))
24 #else
25 #define SAFEINLINE
26 #endif
27
28 static void retype_reply_status(errval_t status, void *st)
29 {
30     struct monitor_blocking_binding *b = (struct monitor_blocking_binding*)st;
31     errval_t err = b->tx_vtbl.remote_cap_retype_response(b, NOP_CONT, status);
32     assert(err_is_ok(err));
33 }
34
35 static void remote_cap_retype(struct monitor_blocking_binding *b,
36                               struct capref croot, capaddr_t src,
37                               uint64_t new_type, uint8_t size_bits,
38                               capaddr_t to, capaddr_t slot, int32_t to_vbits)
39 {
40     capops_retype(new_type, size_bits, croot, to, to_vbits, slot, src,
41                   CPTR_BITS, retype_reply_status, (void*)b);
42 }
43
44 static void delete_reply_status(errval_t status, void *st)
45 {
46     DEBUG_CAPOPS("sending cap_delete reply msg: %s\n", err_getstring(status));
47     struct monitor_blocking_binding *b = (struct monitor_blocking_binding*)st;
48     errval_t err = b->tx_vtbl.remote_cap_delete_response(b, NOP_CONT, status);
49     assert(err_is_ok(err));
50 }
51
52 static void remote_cap_delete(struct monitor_blocking_binding *b,
53                               struct capref croot, capaddr_t src, uint8_t vbits)
54 {
55     struct domcapref cap = { .croot = croot, .cptr = src, .bits = vbits };
56     capops_delete(cap, delete_reply_status, (void*)b);
57 }
58
59 static void revoke_reply_status(errval_t status, void *st)
60 {
61     struct monitor_blocking_binding *b = (struct monitor_blocking_binding*)st;
62     errval_t err = b->tx_vtbl.remote_cap_revoke_response(b, NOP_CONT, status);
63     assert(err_is_ok(err));
64 }
65
66 static void remote_cap_revoke(struct monitor_blocking_binding *b,
67                               struct capref croot, capaddr_t src, uint8_t vbits)
68 {
69     struct domcapref cap = { .croot = croot, .cptr = src, .bits = vbits };
70     capops_revoke(cap, revoke_reply_status, (void*)b);
71 }
72
73 static void rsrc_manifest(struct monitor_blocking_binding *b,
74                           struct capref dispcap, char *str)
75 {
76     errval_t err, err2;
77     rsrcid_t id;
78
79     err = rsrc_new(&id);
80     if(err_is_fail(err)) {
81         goto out;
82     }
83     err = rsrc_join(id, dispcap, b);
84     if(err_is_fail(err)) {
85         // TODO: Cleanup
86         goto out;
87     }
88     err = rsrc_submit_manifest(id, str);
89
90  out:
91     err2 = b->tx_vtbl.rsrc_manifest_response(b, NOP_CONT, id, err);
92     assert(err_is_ok(err2));
93 }
94
95 static void rsrc_phase(struct monitor_blocking_binding *b,
96                        rsrcid_t id, uint32_t phase)
97 {
98     errval_t err;
99
100     err = rsrc_set_phase(id, phase);
101     assert(err_is_ok(err));
102
103     err = b->tx_vtbl.rsrc_phase_response(b, NOP_CONT);
104     assert(err_is_ok(err));
105 }
106
107 static void rpc_rsrc_join(struct monitor_blocking_binding *b,
108                           rsrcid_t id, struct capref dispcap)
109 {
110     errval_t err, err2;
111
112     err = rsrc_join(id, dispcap, b);
113
114     if(err_is_fail(err)) {
115         err2 = b->tx_vtbl.rsrc_join_response(b, NOP_CONT, err);
116         assert(err_is_ok(err2));
117     }
118 }
119
120 static void alloc_monitor_ep(struct monitor_blocking_binding *b)
121 {
122     struct capref retcap = NULL_CAP;
123     errval_t err, reterr = SYS_ERR_OK;
124
125     struct monitor_lmp_binding *lmpb =
126         malloc(sizeof(struct monitor_lmp_binding));
127     assert(lmpb != NULL);
128
129     // setup our end of the binding
130     err = monitor_client_lmp_accept(lmpb, get_default_waitset(),
131                                     DEFAULT_LMP_BUF_WORDS);
132     if (err_is_fail(err)) {
133         free(lmpb);
134         reterr = err_push(err, LIB_ERR_MONITOR_CLIENT_ACCEPT);
135         goto out;
136     }
137
138     retcap = lmpb->chan.local_cap;
139     monitor_server_init(&lmpb->b);
140
141 out:
142     err = b->tx_vtbl.alloc_monitor_ep_response(b, NOP_CONT, reterr, retcap);
143     if (err_is_fail(err)) {
144         USER_PANIC_ERR(err, "failed to send alloc_monitor_ep_reply");
145     }
146 }
147
148 static void cap_identify(struct monitor_blocking_binding *b,
149                          struct capref cap)
150 {
151     errval_t err, reterr;
152
153     union capability_caprep_u u;
154     reterr = monitor_cap_identify(cap, &u.cap);
155
156     /* XXX: shouldn't we skip this if we're being called from the monitor?
157      * apparently not: we make a copy of the cap on LMP to self?!?! */
158     err = cap_destroy(cap);
159     if (err_is_fail(err)) {
160         USER_PANIC_ERR(err, "cap_destroy failed");
161     }
162
163     err = b->tx_vtbl.cap_identify_response(b, NOP_CONT, reterr, u.caprepb);
164     if (err_is_fail(err)) {
165         USER_PANIC_ERR(err, "reply failed");
166     }
167 }
168
169 #define ARM_IRQ_MAX 256
170
171 static void arm_irq_handle_call(struct monitor_blocking_binding *b,
172         struct capref ep, uint32_t irq)
173 {
174
175     errval_t err = 1;
176
177     if (irq <= ARM_IRQ_MAX) {
178         err = invoke_irqtable_set(cap_irq, irq, ep);
179     }
180
181     errval_t err2 = b->tx_vtbl.arm_irq_handle_response(b, NOP_CONT, err);
182     assert(err_is_ok(err2));
183 }
184
185 static void irq_handle_call(struct monitor_blocking_binding *b, struct capref ep)
186 {
187     /* allocate a new slot in the IRQ table */
188     int vec;
189     errval_t err, err2;
190     err = invoke_irqtable_alloc_vector(cap_irq, &vec);
191     if (err_is_fail(err)) {
192         err = err_push(err, MON_ERR_INVOKE_IRQ_ALLOCATE);
193         err2 = b->tx_vtbl.irq_handle_response(b, NOP_CONT, err, 0);
194     }
195     // we got a vector
196
197     /* set it and reply */
198     err = invoke_irqtable_set(cap_irq, vec, ep);
199     if (err_is_fail(err)) {
200         err = err_push(err, MON_ERR_INVOKE_IRQ_SET);        
201     }
202     err2 = b->tx_vtbl.irq_handle_response(b, NOP_CONT, err, vec);
203     assert(err_is_ok(err2));
204 }
205
206 static void get_arch_core_id(struct monitor_blocking_binding *b)
207 {
208     static uintptr_t arch_id = -1;
209     errval_t err;
210 //    printf("%s:%s:%d: \n", __FILE__, __FUNCTION__, __LINE__);
211
212     if (arch_id == -1) {
213         err = invoke_monitor_get_arch_id(&arch_id);
214         assert(err_is_ok(err));
215         assert(arch_id != -1);
216     }
217
218     err = b->tx_vtbl.get_arch_core_id_response(b, NOP_CONT, arch_id);
219     assert(err_is_ok(err));
220 }
221
222 struct pending_reply {
223     struct monitor_blocking_binding *b;
224     errval_t err;
225 };
226
227 static void retry_reply(void *arg)
228 {
229     struct pending_reply *r = arg;
230     assert(r != NULL);
231     struct monitor_blocking_binding *b = r->b;
232     errval_t err;
233
234     err = b->tx_vtbl.cap_set_remote_response(b, NOP_CONT, r->err);
235     if (err_is_ok(err)) {
236         free(r);
237     } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
238         err = b->register_send(b, get_default_waitset(), MKCONT(retry_reply, r));
239         assert(err_is_ok(err));
240     } else {
241         DEBUG_ERR(err, "failed to reply to memory request");
242     }
243 }
244
245 static void cap_set_remote(struct monitor_blocking_binding *b,
246                            struct capref cap, bool remote)
247 {
248     errval_t err, reterr;
249
250     reterr = monitor_remote_relations(cap, RRELS_COPY_BIT, RRELS_COPY_BIT, NULL);
251
252     err = b->tx_vtbl.cap_set_remote_response(b, NOP_CONT, reterr);
253     if(err_is_fail(err)) {
254         if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
255             struct pending_reply *r = malloc(sizeof(struct pending_reply));
256             assert(r != NULL);
257             r->b = b;
258             r->err = reterr;
259             err = b->register_send(b, get_default_waitset(), MKCONT(retry_reply, r));
260             assert(err_is_ok(err));
261         } else {
262             USER_PANIC_ERR(err, "cap_set_remote_response");
263         }
264     }
265 }
266
267 /* ----------------------- BOOTINFO REQUEST CODE START ---------------------- */
268
269 static void get_phyaddr_cap(struct monitor_blocking_binding *b)
270 {
271     // XXX: We should not just hand out this cap to everyone
272     // who requests it. There is currently no way to determine
273     // if the client is a valid recipient
274     errval_t err;
275
276     struct capref src = {
277         .cnode = cnode_root,
278         .slot  = ROOTCN_SLOT_PACN
279     };
280
281     err = b->tx_vtbl.get_phyaddr_cap_response(b, NOP_CONT, src,
282             SYS_ERR_OK);
283     if (err_is_fail(err)) {
284         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
285             err = b->register_send(b, get_default_waitset(),
286                                    MKCONT((void (*)(void *))get_phyaddr_cap, b));
287             if (err_is_fail(err)) {
288                 USER_PANIC_ERR(err, "register_send failed");
289             }
290         }
291
292         USER_PANIC_ERR(err, "sending get_phyaddr_cap_response failed");
293     }
294 }
295
296 static void get_io_cap(struct monitor_blocking_binding *b)
297 {
298     // XXX: We should not just hand out this cap to everyone
299     // who requests it. There is currently no way to determine
300     // if the client is a valid recipient
301     errval_t err;
302     struct capref src = {
303         .cnode = cnode_task,
304         .slot  = TASKCN_SLOT_IO
305     };
306
307     err = b->tx_vtbl.get_io_cap_response(b, NOP_CONT, src,
308             SYS_ERR_OK);
309     if (err_is_fail(err)) {
310         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
311             err = b->register_send(b, get_default_waitset(),
312                                    MKCONT((void (*)(void *))get_io_cap, b));
313             if (err_is_fail(err)) {
314                 USER_PANIC_ERR(err, "register_send failed");
315             }
316         }
317
318         USER_PANIC_ERR(err, "sending get_io_cap_response failed");
319     }
320 }
321
322
323 static void get_bootinfo(struct monitor_blocking_binding *b)
324 {
325     errval_t err;
326
327     struct capref frame = {
328         .cnode = cnode_task,
329         .slot  = TASKCN_SLOT_BOOTINFO
330     };
331
332     struct frame_identity id = { .base = 0, .bits = 0 };
333     err = invoke_frame_identify(frame, &id);
334     assert(err_is_ok(err));
335
336     err = b->tx_vtbl.get_bootinfo_response(b, NOP_CONT, SYS_ERR_OK, frame,
337                                            (size_t)1 << id.bits);
338     if (err_is_fail(err)) {
339         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
340             err = b->register_send(b, get_default_waitset(),
341                                    MKCONT((void (*)(void *))get_bootinfo, b));
342             if (err_is_fail(err)) {
343                 USER_PANIC_ERR(err, "register_send failed");
344             }
345         }
346
347         USER_PANIC_ERR(err, "sending get_bootinfo_response failed");
348     }
349 }
350
351 /* ----------------------- BOOTINFO REQUEST CODE END ----------------------- */
352
353 static void get_ipi_cap(struct monitor_blocking_binding *b)
354 {
355     errval_t err;
356
357     // XXX: We should not just hand out this cap to everyone
358     // who requests it. There is currently no way to determine
359     // if the client is a valid recipient
360
361     err = b->tx_vtbl.get_ipi_cap_response(b, NOP_CONT, cap_ipi);
362     assert(err_is_ok(err));
363 }
364
365 // XXX: these look suspicious in combination with distops!
366 static void forward_kcb_request(struct monitor_blocking_binding *b,
367                                 coreid_t destination, struct capref kcb)
368 {
369     printf("%s:%s:%d: forward_kcb_request in monitor\n",
370            __FILE__, __FUNCTION__, __LINE__);
371
372     errval_t err = SYS_ERR_OK;
373
374     struct capability kcb_cap;
375     err = monitor_cap_identify(kcb, &kcb_cap);
376     if (err_is_fail(err)) {
377         DEBUG_ERR(err, "monitor_cap_identify failed");
378         err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err);
379         assert(err_is_ok(err));
380         return;
381     }
382
383     if (destination == my_core_id) {
384         uintptr_t kcb_base = (uintptr_t)kcb_cap.u.kernelcontrolblock.kcb;
385         printf("%s:%s:%d: Invoke syscall directly, destination==my_core_id; kcb_base = 0x%"PRIxPTR"\n",
386                __FILE__, __FUNCTION__, __LINE__, kcb_base);
387         err = invoke_monitor_add_kcb(kcb_base);
388         if (err_is_fail(err)) {
389             USER_PANIC_ERR(err, "invoke_montitor_add_kcb failed.");
390         }
391
392         err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err);
393         assert(err_is_ok(err));
394         return;
395     }
396
397     struct intermon_binding *ib;
398     err = intermon_binding_get(destination, &ib);
399     if (err_is_fail(err)) {
400         DEBUG_ERR(err, "intermon_binding_get failed");
401         err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err);
402         assert(err_is_ok(err));
403         return;
404     }
405
406     intermon_caprep_t kcb_rep;
407     capability_to_caprep(&kcb_cap, &kcb_rep);
408
409     ib->st = b;
410     err = ib->tx_vtbl.give_kcb_request(ib, NOP_CONT, kcb_rep);
411     if (err_is_fail(err)) {
412         DEBUG_ERR(err, "give_kcb send failed");
413         err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err);
414         assert(err_is_ok(err));
415         return;
416     }
417 }
418
419 static void forward_kcb_rm_request(struct monitor_blocking_binding *b,
420                                    coreid_t destination, struct capref kcb)
421 {
422     errval_t err = SYS_ERR_OK;
423
424     // can't move ourselves
425     assert(destination != my_core_id);
426
427     struct capability kcb_cap;
428     err = monitor_cap_identify(kcb, &kcb_cap);
429     if (err_is_fail(err)) {
430         DEBUG_ERR(err, "monitor_cap_identify failed");
431         err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err);
432         assert(err_is_ok(err));
433         return;
434     }
435
436     struct intermon_binding *ib;
437     err = intermon_binding_get(destination, &ib);
438     if (err_is_fail(err)) {
439         DEBUG_ERR(err, "intermon_binding_get failed");
440         err = b->tx_vtbl.forward_kcb_request_response(b, NOP_CONT, err);
441         assert(err_is_ok(err));
442         return;
443     }
444     uintptr_t kcb_base = (uintptr_t )kcb_cap.u.kernelcontrolblock.kcb;
445
446     // send request to other monitor
447     // remember monitor binding to send answer
448     struct intermon_state *ist = (struct intermon_state*)ib->st;
449     ist->originating_client = (struct monitor_binding*)b; //XXX: HACK
450     err = ib->tx_vtbl.forward_kcb_rm_request(ib, NOP_CONT, kcb_base);
451     assert(err_is_ok(err));
452 }
453
454 static void get_global_paddr(struct monitor_blocking_binding *b)
455 {
456     genpaddr_t global = 0;
457     errval_t err;
458     err = invoke_get_global_paddr(cap_kernel, &global);
459     if (err_is_fail(err)) {
460         DEBUG_ERR(err, "get_global_paddr invocation");
461     }
462
463     err = b->tx_vtbl.get_global_paddr_response(b, NOP_CONT, global);
464     if (err_is_fail(err)) {
465         USER_PANIC_ERR(err, "sending global paddr failed.");
466     }
467 }
468
469 /*------------------------- Initialization functions -------------------------*/
470
471 static struct monitor_blocking_rx_vtbl rx_vtbl = {
472     .get_bootinfo_call = get_bootinfo,
473     .get_phyaddr_cap_call = get_phyaddr_cap,
474     .get_io_cap_call = get_io_cap,
475
476     .remote_cap_retype_call  = remote_cap_retype,
477     .remote_cap_delete_call  = remote_cap_delete,
478     .remote_cap_revoke_call  = remote_cap_revoke,
479
480     .rsrc_manifest_call      = rsrc_manifest,
481     .rsrc_join_call          = rpc_rsrc_join,
482     .rsrc_phase_call         = rsrc_phase,
483
484     .alloc_monitor_ep_call   = alloc_monitor_ep,
485     .cap_identify_call       = cap_identify,
486     .irq_handle_call         = irq_handle_call,
487     .arm_irq_handle_call     = arm_irq_handle_call,
488     .get_arch_core_id_call   = get_arch_core_id,
489
490     .cap_set_remote_call     = cap_set_remote,
491     .get_ipi_cap_call = get_ipi_cap,
492
493     .forward_kcb_request_call = forward_kcb_request,
494
495     .forward_kcb_rm_request_call = forward_kcb_rm_request,
496
497     .get_global_paddr_call = get_global_paddr,
498 };
499
500 static void export_callback(void *st, errval_t err, iref_t iref)
501 {
502     assert(err_is_ok(err));
503     set_monitor_rpc_iref(iref);
504 }
505
506 static errval_t connect_callback(void *st, struct monitor_blocking_binding *b)
507 {
508     b->rx_vtbl = rx_vtbl;
509
510     // TODO: set error handler
511     return SYS_ERR_OK;
512 }
513
514 errval_t monitor_rpc_init(void)
515 {
516     static struct monitor_blocking_export e = {
517         .connect_cb = connect_callback,
518         .common = {
519             .export_callback = export_callback,
520             .flags = IDC_EXPORT_FLAGS_DEFAULT,
521             .connect_cb_st = &e,
522             .lmp_connect_callback = monitor_blocking_lmp_connect_handler,
523         }
524     };
525
526     e.waitset = get_default_waitset();
527
528     return idc_export_service(&e.common);
529 }