libgmp: remove dependency to libbarrelfish
[barrelfish] / usr / monitor / capops / retype.c
1 /*
2  * Copyright (c) 2012 ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 #include <barrelfish/barrelfish.h>
11 #include <barrelfish/caddr.h>
12 #include <if/intermon_defs.h>
13 #include <monitor.h>
14 #include <monitor_invocations.h>
15 #include <dom_invocations.h>
16 #include "capops.h"
17 #include "capsend.h"
18 #include "caplock.h"
19 #include "magic.h"
20 #include "internal.h"
21
22 /*
23  * Retype states
24  */
25
26 struct retype_check_st {
27     enum objtype type;
28     size_t objbits;
29     struct domcapref src;
30     struct result_closure cont;
31 };
32
33 struct retype_output_st {
34     struct domcapref destcn;
35     cslot_t start_slot;
36     struct result_closure cont;
37 };
38
39 struct requested_retype_st {
40     struct intermon_msg_queue_elem queue_elem;
41     struct retype_check_st check;
42     struct capref src;
43     coreid_t from;
44     errval_t status;
45     genvaddr_t request_st;
46 };
47
48 struct local_retype_st {
49     struct retype_check_st check;
50     struct retype_output_st output;
51 };
52
53 struct retype_request_st {
54     struct intermon_msg_queue_elem queue_elem;
55     intermon_caprep_t caprep;
56     struct retype_check_st check;
57     struct retype_output_st output;
58 };
59
60 /*
61  * Prototypes for static functions so ordering does not matter
62  */
63
64 static void check_retype__enq(struct retype_check_st *check_st);
65 static void retype_check__rx(errval_t status, struct retype_check_st* check,
66                              struct retype_output_st *output, void *to_free);
67
68 /**
69  * \brief Intermon is ready to send retype result
70  */
71 static void
72 retype_result__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
73 {
74     errval_t err;
75     struct requested_retype_st *req_st = (struct requested_retype_st*)e;
76     err = intermon_capops_retype_response__tx(b, NOP_CONT, req_st->status,
77                                               req_st->request_st);
78
79     if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
80         DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
81         struct intermon_state *inter_st = (struct intermon_state *)b->st;
82         // requeue send request at front and return
83         err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
84                                              (struct msg_queue_elem *)e);
85         GOTO_IF_ERR(err, handle_err);
86         return;
87     }
88
89 handle_err:
90     PANIC_IF_ERR(err, "sending retype result message");
91     free(req_st);
92 }
93
94 /**
95  * \brief Enqueue retype result
96  */
97 static void
98 retype_result__enq(struct requested_retype_st *req_st)
99 {
100     req_st->queue_elem.cont = retype_result__send;
101     errval_t err = capsend_target(req_st->from, (struct msg_queue_elem*)req_st);
102     if (err_is_fail(err)) {
103         DEBUG_ERR(err, "failed to enqueue retype result");
104         free(req_st);
105     }
106 }
107
108 /**
109  * \brief Retype temporary cap has been deleted
110  */
111 static void
112 retype_tmpcap_delete__cont(errval_t status, void *st)
113 {
114     errval_t err;
115     struct requested_retype_st *req_st = (struct requested_retype_st*)st;
116
117     if (err_is_fail(status) && err_no(status) != SYS_ERR_CAP_NOT_FOUND) {
118         DEBUG_ERR(status, "deleting tmp retype cap, cap will leak");
119     }
120
121     err = slot_free(req_st->src);
122     DEBUG_IF_ERR(err, "freeing tmp retype slot, slot will leak");
123     req_st->src = NULL_CAP;
124     memset(&req_st->check.src, 0, sizeof(struct domcapref));
125
126     retype_result__enq(req_st);
127 }
128
129 /**
130  * \brief The check for a retype request has completed
131  */
132 static void
133 retype_request_check__rx(errval_t status, void *st)
134 {
135     struct requested_retype_st *req_st = (struct requested_retype_st*)st;
136
137     if (err_is_ok(status)) {
138         status = monitor_remote_relations(req_st->src, RRELS_DESC_BIT,
139                                           RRELS_DESC_BIT, NULL);
140     }
141
142     req_st->status = status;
143
144     if (!capref_is_null(req_st->src)) {
145         capops_delete(req_st->check.src, retype_tmpcap_delete__cont, req_st);
146     }
147     else {
148         retype_result__enq(req_st);
149     }
150 }
151
152 void
153 retype_request__rx(struct intermon_binding *b, intermon_caprep_t srcrep,
154                    uint32_t desttype, uint32_t destbits, genvaddr_t st)
155 {
156     errval_t err;
157
158     // allocate and setup state
159     struct requested_retype_st *req_st;
160     err = calloce(1, sizeof(*req_st), &req_st);
161     PANIC_IF_ERR(err, "allocating retype request state");
162
163     req_st->queue_elem.cont = retype_result__send;
164     req_st->check.type = desttype;
165     req_st->check.objbits = destbits;
166     req_st->check.cont = MKRESCONT(retype_request_check__rx, req_st);
167     req_st->from = ((struct intermon_state*)b->st)->core_id;
168     req_st->request_st = st;
169
170     // get slot and cap
171     err = slot_alloc(&req_st->src);
172     GOTO_IF_ERR(err, cont_err);
173     req_st->check.src = get_cap_domref(req_st->src);
174
175     struct capability cap;
176     caprep_to_capability(&srcrep, &cap);
177     err = monitor_copy_if_exists(&cap, req_st->src);
178     GOTO_IF_ERR(err, cont_err);
179
180     // validate cap state
181     distcap_state_t state;
182     err = dom_cnode_get_state(req_st->check.src, &state);
183     GOTO_IF_ERR(err, cont_err);
184
185     if (distcap_state_is_foreign(state)) {
186         err = MON_ERR_CAP_FOREIGN;
187         goto cont_err;
188     }
189     if (distcap_state_is_busy(state)) {
190         err = MON_ERR_REMOTE_CAP_RETRY;
191         goto cont_err;
192     }
193
194     // initiate check
195     check_retype__enq(&req_st->check);
196
197     return;
198
199 cont_err:
200     retype_request_check__rx(err, req_st);
201 }
202
203 static void
204 retype_result__rx(errval_t status, struct retype_request_st *req_st)
205 {
206     retype_check__rx(status, &req_st->check, &req_st->output, req_st);
207 }
208
209 /**
210  * \brief Handle the response to a retype request
211  */
212 void
213 retype_response__rx(struct intermon_binding *b, errval_t status, genvaddr_t st)
214 {
215     struct retype_request_st *req_st = (struct retype_request_st*)(lvaddr_t)st;
216     retype_result__rx(status, req_st);
217 }
218
219 /**
220  * \brief Intermon is ready to send request_retype
221  */
222 static void
223 retype_request__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
224 {
225     struct retype_request_st *req_st = (struct retype_request_st*)e;
226     errval_t err;
227
228     err = intermon_capops_request_retype__tx(b, NOP_CONT, req_st->caprep,
229                                              req_st->check.type,
230                                              req_st->check.objbits,
231                                              (lvaddr_t)req_st);
232
233
234     if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
235         DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
236         struct intermon_state *inter_st = (struct intermon_state *)b->st;
237         // requeue send request at front and return
238         err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
239                                              (struct msg_queue_elem *)e);
240         GOTO_IF_ERR(err, handle_err);
241         return;
242     }
243
244 handle_err:
245     if (err_is_fail(err)) {
246         retype_result__rx(err, req_st);
247     }
248 }
249
250 /**
251  * \brief Enqueue a retype request
252  */
253 static void
254 retype_request__enq(struct retype_request_st *req_st)
255 {
256     errval_t err;
257     struct capability cap;
258     err = monitor_domains_cap_identify(req_st->check.src.croot,
259                                        req_st->check.src.cptr,
260                                        req_st->check.src.bits, &cap);
261     GOTO_IF_ERR(err, err_cont);
262
263     req_st->queue_elem.cont = retype_request__send;
264     capability_to_caprep(&cap, &req_st->caprep);
265
266     err = capsend_owner(req_st->check.src, (struct msg_queue_elem*)req_st);
267     GOTO_IF_ERR(err, err_cont);
268
269     return;
270
271 err_cont:
272     retype_result__rx(err, req_st);
273 }
274
275 /**
276  * \brief The descendants search has completed
277  */
278 static void
279 find_descendants__rx(errval_t status, void *st)
280 {
281     struct retype_check_st *check_st = (struct retype_check_st*)st;
282
283     // need to translate error codes:
284     // - descendants found -> revoke first
285     // - not found -> ok
286     // - otherwise -> unchanged
287     if (err_is_ok(status)) {
288         status = SYS_ERR_REVOKE_FIRST;
289     }
290     else if (err_no(status) == SYS_ERR_CAP_NOT_FOUND) {
291         status = err_push(status, SYS_ERR_OK);
292     }
293
294     // unlock cap and procede with check result continuation
295     caplock_unlock(check_st->src);
296     CALLRESCONT(check_st->cont, status);
297 }
298
299 /**
300  * \brief Enqueue a retype check
301  */
302 static void
303 check_retype__enq(struct retype_check_st *check_st)
304 {
305     errval_t err;
306
307     if (check_st->type == ObjType_EndPoint) {
308         // XXX: because of the current "multi-retype" hack for endpoints, a
309         // dispatcher->endpoint retype can happen irrespective of the existence
310         // of descendents on any core.
311         err = monitor_domcap_remote_relations(check_st->src.croot,
312                                               check_st->src.cptr,
313                                               check_st->src.bits,
314                                               RRELS_DESC_BIT,
315                                               RRELS_DESC_BIT, NULL);
316         goto cont_err;
317     }
318
319     err = monitor_lock_cap(check_st->src.croot, check_st->src.cptr,
320                            check_st->src.bits);
321     GOTO_IF_ERR(err, cont_err);
322
323     err = capsend_find_descendants(check_st->src, find_descendants__rx,
324                                    check_st);
325     GOTO_IF_ERR(err, unlock_cap);
326
327     return;
328
329 unlock_cap:
330     caplock_unlock(check_st->src);
331
332 cont_err:
333     CALLRESCONT(check_st->cont, err);
334 }
335
336 /**
337  * \brief Handle a completed retype check
338  */
339 static void
340 retype_check__rx(errval_t status, struct retype_check_st* check,
341                  struct retype_output_st *output, void *to_free)
342 {
343     errval_t err = status;
344     if (err_is_ok(err)) {
345         // the retype may procede
346         struct domcapref *src = &check->src;
347         struct domcapref *destcn = &output->destcn;
348         assert(capcmp(src->croot, destcn->croot));
349         err = monitor_create_caps(src->croot, check->type, check->objbits,
350                                   src->cptr, src->bits, destcn->cptr,
351                                   destcn->bits, output->start_slot);
352     }
353     struct result_closure cont = output->cont;
354     assert(cont.handler);
355     free(to_free);
356     CALLRESCONT(cont, err);
357 }
358
359 /**
360  * \brief Handle result of a owner-initiated retype check.
361  */
362 static void
363 local_retype_check__rx(errval_t status, void *st)
364 {
365     struct local_retype_st *rtp_st = (struct local_retype_st*)st;
366     retype_check__rx(status, &rtp_st->check, &rtp_st->output, rtp_st);
367 }
368
369 /*
370  * Entry
371  */
372
373 void
374 capops_retype(enum objtype type, size_t objbits, struct capref croot,
375               capaddr_t dest_cn, uint8_t dest_bits, cslot_t dest_slot,
376               capaddr_t src, uint8_t src_bits,
377               retype_result_handler_t result_handler, void *st)
378 {
379     errval_t err;
380     distcap_state_t src_state;
381     struct retype_request_st *rtp_req_st;
382     struct local_retype_st *rtp_loc_st;
383
384     err = invoke_cnode_get_state(croot, src, src_bits, &src_state);
385     GOTO_IF_ERR(err, err_cont);
386
387     if (distcap_state_is_busy(src_state)) {
388         err = MON_ERR_REMOTE_CAP_RETRY;
389         goto err_cont;
390     }
391
392     err = invoke_cnode_retype(croot, src, type, objbits, dest_cn, dest_slot,
393                               dest_bits);
394     if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) {
395         goto err_cont;
396     }
397
398     // if retype invocation failed with "retry through mon", we assume that
399     // distcap_needs_locality(cap) would return true.
400
401     if (distcap_state_is_foreign(src_state)) {
402         // setup retype request
403         err = calloce(1, sizeof(*rtp_req_st), &rtp_req_st);
404         GOTO_IF_ERR(err, err_cont);
405
406         // fill in parameters
407         rtp_req_st->check.type = type;
408         rtp_req_st->check.objbits = objbits;
409         rtp_req_st->check.src = (struct domcapref){
410             .croot = croot,
411             .cptr = src,
412             .bits = src_bits,
413         };
414         rtp_req_st->output.destcn = (struct domcapref){
415             .croot = croot,
416             .cptr = dest_cn,
417             .bits = dest_bits,
418         };
419         rtp_req_st->output.start_slot = dest_slot;
420         rtp_req_st->output.cont = MKRESCONT(result_handler, st);
421
422         // enqueue retype request
423         retype_request__enq(rtp_req_st);
424     }
425     else {
426         // on owner, setup retype check
427         err = calloce(1, sizeof(*rtp_loc_st), &rtp_loc_st);
428         GOTO_IF_ERR(err, err_cont);
429
430         // fill in parameters
431         rtp_loc_st->check.type = type;
432         rtp_loc_st->check.objbits = objbits;
433         rtp_loc_st->check.src = (struct domcapref){
434             .croot = croot,
435             .cptr = src,
436             .bits = src_bits,
437         };
438         rtp_loc_st->output.destcn = (struct domcapref){
439             .croot = croot,
440             .cptr = dest_cn,
441             .bits = dest_bits,
442         };
443         rtp_loc_st->output.start_slot = dest_slot;
444         rtp_loc_st->output.cont = MKRESCONT(result_handler, st);
445
446         // setup handler for retype check result
447         rtp_loc_st->check.cont = MKRESCONT(local_retype_check__rx, rtp_loc_st);
448
449         // initiate check
450         check_retype__enq(&rtp_loc_st->check);
451     }
452
453     return;
454
455 err_cont:
456     result_handler(err, st);
457 }
458