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