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