332fb379ea87c7c37e7887e2f41352f23c3a46de
[barrelfish] / usr / monitor / capops / retrieve.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 <if/intermon_defs.h>
12 #include "monitor.h"
13 #include "capops.h"
14 #include "capsend.h"
15 #include "magic.h"
16 #include "caplock.h"
17 #include "internal.h"
18 #include "dom_invocations.h"
19 #include "monitor_invocations.h"
20
21 struct retrieve_rpc_st {
22     struct intermon_msg_queue_elem iqn;
23     struct domcapref cap;
24     struct capability rawcap;
25     move_result_handler_t result_handler;
26     void *st;
27     coreid_t prev_owner;
28 };
29
30 struct retrieve_response_st {
31     struct intermon_msg_queue_elem iqn;
32     errval_t status;
33     uint8_t relations;
34     genvaddr_t st;
35     coreid_t from;
36 };
37
38 static void retrieve_owner__enq(struct retrieve_rpc_st *st);
39 static void retrieve_owner__send(struct intermon_binding *b,
40                                  struct intermon_msg_queue_elem *e);
41 static void retrieve_result__enq(errval_t status,
42                                  struct retrieve_response_st *st);
43 static void retrieve_result__send(struct intermon_binding *b,
44                                   struct intermon_msg_queue_elem *e);
45 static void retrieve_ownership_update__fin(void *st);
46
47 void
48 capops_retrieve(struct domcapref cap,
49                 move_result_handler_t result_handler,
50                 void *st)
51 {
52     errval_t err;
53
54     distcap_state_t state;
55     err = dom_cnode_get_state(cap, &state);
56     GOTO_IF_ERR(err, report_error);
57     if (distcap_state_is_busy(state)) {
58         err = MON_ERR_REMOTE_CAP_RETRY;
59     }
60     if (distcap_state_is_foreign(state)) {
61         err = MON_ERR_CAP_FOREIGN;
62     }
63     GOTO_IF_ERR(err, report_error);
64
65     err = monitor_lock_cap(cap.croot, cap.cptr, cap.bits);
66     GOTO_IF_ERR(err, report_error);
67
68     struct retrieve_rpc_st *rst = NULL;
69     err = calloce(1, sizeof(*rst), &rst);
70     GOTO_IF_ERR(err, unlock_cap);
71
72     rst->cap = cap;
73     rst->result_handler = result_handler;
74     rst->st = st;
75
76     err = monitor_get_domcap_owner(cap, &rst->prev_owner);
77     GOTO_IF_ERR(err, free_st);
78
79     if (rst->prev_owner == my_core_id) {
80         err = SYS_ERR_OK;
81         goto free_st;
82     }
83
84     retrieve_owner__enq(rst);
85
86     return;
87
88 free_st:
89     free(rst);
90
91 unlock_cap:
92     caplock_unlock(cap);
93
94 report_error:
95     result_handler(err, st);
96 }
97
98 static void
99 retrieve_ownership__rx(errval_t status, struct retrieve_rpc_st *st)
100 {
101     caplock_unlock(st->cap);
102     st->result_handler(status, st->st);
103     free(st);
104 }
105
106 static void
107 retrieve_owner__enq(struct retrieve_rpc_st *st)
108 {
109     errval_t err;
110
111     st->iqn.cont = retrieve_owner__send;
112     err = capsend_owner(st->cap, (struct msg_queue_elem*)st);
113     if (err_is_fail(err)) {
114         retrieve_ownership__rx(err, st);
115     }
116 }
117
118 static void
119 retrieve_owner__send(struct intermon_binding *b,
120                      struct intermon_msg_queue_elem *e)
121 {
122     errval_t err;
123     struct retrieve_rpc_st *st = (struct retrieve_rpc_st*)e;
124     intermon_caprep_t caprep;
125
126     err = monitor_set_domcap_owner(st->cap, my_core_id);
127     GOTO_IF_ERR(err, report_error);
128
129     capability_to_caprep(&st->rawcap, &caprep);
130     err = intermon_capops_retrieve_request__tx(b, NOP_CONT, caprep, (lvaddr_t)st);
131     GOTO_IF_ERR(err, report_error);
132
133     return;
134
135 report_error:
136     retrieve_ownership__rx(err, st);
137 }
138
139 void
140 retrieve_request__rx(struct intermon_binding *b,
141                      intermon_caprep_t caprep,
142                      genvaddr_t st)
143 {
144     errval_t err, err2;
145     struct intermon_state *inter_st = (struct intermon_state*)b->st;
146
147     struct retrieve_response_st *rst;
148     err = calloce(1, sizeof(*rst), &rst);
149     PANIC_IF_ERR(err, "allocating retrieve respones state");
150     rst->st = st;
151     rst->from = inter_st->core_id;
152
153     struct capability rawcap;
154     caprep_to_capability(&caprep, &rawcap);
155
156     struct capref cap;
157     err = slot_alloc(&cap);
158     GOTO_IF_ERR(err, respond_err);
159
160     err = monitor_copy_if_exists(&rawcap, cap);
161     GOTO_IF_ERR(err, free_slot);
162
163     distcap_state_t state;
164     err = dom_cnode_get_state(get_cap_domref(cap), &state);
165     GOTO_IF_ERR(err, delete_cap);
166
167     if (distcap_state_is_busy(state)) {
168         err = MON_ERR_REMOTE_CAP_RETRY;
169         goto delete_cap;
170     }
171     if (distcap_state_is_foreign(state)) {
172         err = MON_ERR_CAP_FOREIGN;
173         goto delete_cap;
174     }
175
176     uint8_t relations, remote_relations;
177     err = monitor_cap_has_relations(cap, 0xFF, &relations);
178     GOTO_IF_ERR(err, delete_cap);
179
180     err = monitor_remote_relations(cap, 0, 0, &remote_relations);
181     GOTO_IF_ERR(err, delete_cap);
182
183     rst->relations = relations | remote_relations | RRELS_COPY_BIT;
184
185     err = monitor_set_cap_owner(cap_root, get_cap_addr(cap),
186                                 get_cap_valid_bits(cap),
187                                 rst->from);
188
189 delete_cap:
190     err2 = cap_delete(cap);
191     DEBUG_IF_ERR(err2, "while deleting temp cap for retrieve");
192
193 free_slot:
194     err2 = slot_free(cap);
195     DEBUG_IF_ERR(err2, "freeing temp cap slot for retrieve");
196
197 respond_err:
198     retrieve_result__enq(err, rst);
199 }
200
201 static void
202 retrieve_result__enq(errval_t status, struct retrieve_response_st *st)
203 {
204     errval_t err;
205     st->status = status;
206     st->iqn.cont = retrieve_result__send;
207
208     err = capsend_target(st->from, (struct msg_queue_elem*)st);
209     PANIC_IF_ERR(err, "enqueing retrieve result");
210 }
211
212 static void
213 retrieve_result__send(struct intermon_binding *b,
214                       struct intermon_msg_queue_elem *e)
215 {
216     errval_t err;
217     struct retrieve_response_st *st = (struct retrieve_response_st*)e;
218
219     err = intermon_capops_retrieve_result__tx(b, NOP_CONT, st->status,
220                                               st->relations, st->st);
221     PANIC_IF_ERR(err, "sending retrieve result");
222     free(st);
223 }
224
225 void
226 retrieve_result__rx(struct intermon_binding *b, errval_t status,
227                     uint8_t relations, genvaddr_t st)
228 {
229     errval_t err;
230     struct retrieve_rpc_st *rst = (struct retrieve_rpc_st*)(lvaddr_t)st;
231
232     if (err_is_fail(status)) {
233         err = status;
234         goto report_error;
235     }
236
237     err = monitor_domcap_remote_relations(rst->cap.croot, rst->cap.cptr,
238                                           rst->cap.bits, relations, 0xFF,
239                                           NULL);
240     PANIC_IF_ERR(err, "setting rrels for retrieved cap");
241
242     struct event_closure updated_cont
243         = MKCONT(retrieve_ownership_update__fin, rst);
244     err = capsend_update_owner(rst->cap, updated_cont);
245     PANIC_IF_ERR(err, "updating retrieve ownership");
246
247 report_error:
248     retrieve_ownership__rx(err, rst);
249 }
250
251 static void
252 retrieve_ownership_update__fin(void *st)
253 {
254     struct retrieve_rpc_st *rst = (struct retrieve_rpc_st*)st;
255
256     retrieve_ownership__rx(SYS_ERR_OK, rst);
257 }