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