1/**
2 * \file
3 * \brief
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2010, 2011, 2012, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include "monitor.h"
16#include "capops.h"
17#include <if/monitor_mem_defs.h>
18#include <if/monitor_mem_defs.h>
19#include <if/mem_defs.h>
20
21static uint8_t mem_core_id;
22static struct monitor_mem_binding *monitor_mem_client;
23static bool mem_setup_complete = false;
24iref_t monitor_mem_iref = 0;
25
26static void mem_alloc_delete_result_handler(errval_t status, void *st)
27{
28    struct capref *cap = (struct capref*)st;
29    errval_t err;
30
31    if (err_is_fail(status)) {
32        DEBUG_ERR(status, "capops_delete failed, cap will leak");
33    }
34    else {
35        err = slot_free(*cap);
36        if (err_is_fail(err)) {
37            DEBUG_ERR(err, "slot_free failed, cap will leak");
38        }
39    }
40
41    free(cap);
42}
43
44/**
45 * \brief Request for some memory (over the memory allocation channel)
46 */
47static errval_t mem_alloc_handler(struct monitor_mem_binding *b,
48                              uint8_t size_bits, genpaddr_t minbase,
49                              genpaddr_t maxlimit, coreid_t from,
50                              errval_t *out_err, monitor_mem_caprep_t *out_caprep)
51{
52    struct capref *cap = NULL;
53    monitor_mem_caprep_t caprep = {0,0,0,0};
54    errval_t err;
55    errval_t reterr = SYS_ERR_OK;
56
57    /* This should only run on the core with the mem_serv. Or else the system
58       will deadlock. */
59    assert(bsp_monitor);
60
61    cap = malloc(sizeof(*cap));
62    if (!cap) {
63        reterr = LIB_ERR_MALLOC_FAIL;
64        goto out;
65    }
66
67    err = ram_alloc(cap, size_bits);
68    if (err_is_fail(err)) {
69        reterr = err_push(err, LIB_ERR_RAM_ALLOC);
70        goto out;
71    }
72
73    struct capability cap_raw;
74    err = monitor_cap_identify(*cap, &cap_raw);
75    if (err_is_fail(err)) {
76        reterr = err_push(err, MON_ERR_CAP_IDENTIFY);
77        goto out;
78    }
79    assert(cap_raw.type == ObjType_RAM);
80    intermon_caprep_t caprep2;
81    capability_to_caprep(&cap_raw, &caprep2);
82    // XXX: work around stupid flounder behaviour: these types are identical!
83    STATIC_ASSERT_SIZEOF(caprep, sizeof(caprep2));
84    memcpy(&caprep, &caprep2, sizeof(caprep));
85
86    err = monitor_set_cap_owner(cap_root, get_cap_addr(*cap), get_cap_level(*cap), from);
87    if (err_is_fail(err)) {
88        reterr = err;
89        memset(&caprep, 0, sizeof(caprep));
90    }
91
92out:
93    // RPC protocol, this can never fail with TX_BUSY
94    *out_err = reterr;
95    *out_caprep = caprep;
96    // err = b->tx_vtbl.alloc_response(b, NOP_CONT, reterr, caprep);
97    // if (err_is_fail(err)) {
98    //     DEBUG_ERR(err, "reply failed");
99    // }
100
101    if (cap) {
102        capops_delete(get_cap_domref(*cap), mem_alloc_delete_result_handler, cap);
103    }
104    return SYS_ERR_OK;
105}
106
107static errval_t mem_free_handler(struct monitor_mem_binding *b,
108                             monitor_mem_caprep_t caprep,
109                             genpaddr_t base, uint8_t bits, errval_t *result)
110{
111    errval_t err;
112    // this should only run on the bsp monitor
113    assert(bsp_monitor);
114    DEBUG_CAPOPS("%s\n", __FUNCTION__);
115
116    // convert caprep into cap
117    intermon_caprep_t caprep2;
118    // XXX: work around stupid flounder behaviour: these types are identical!
119    STATIC_ASSERT_SIZEOF(caprep, sizeof(caprep2));
120    memcpy(&caprep2, &caprep, sizeof(caprep));
121    struct capability cap_raw;
122    caprep_to_capability(&caprep2, &cap_raw);
123
124    DEBUG_CAPOPS("%s: freeing:\n", __FUNCTION__);
125    debug_print_caprep(&caprep2);
126
127    assert(ObjType_RAM == cap_raw.type);
128
129    struct capref cap;
130    err = slot_alloc(&cap);
131    if (err_is_fail(err)) {
132        *result = err_push(err, LIB_ERR_SLOT_ALLOC);
133        goto out;
134    }
135
136    err = monitor_cap_create(cap, &cap_raw, my_core_id);
137    if (err_is_fail(err)) {
138        *result = err_push(err, MON_ERR_CAP_CREATE);
139        goto out;
140    }
141    DEBUG_CAPOPS("%s: created local copy, sending to memserv\n", __FUNCTION__);
142
143    struct mem_binding *mb = get_mem_client();
144    assert(mb);
145    err = mb->rpc_tx_vtbl.free_monitor(mb, cap, base, bits, result);
146    if (err_is_fail(err)) {
147        *result = err;
148    }
149out:
150    DEBUG_CAPOPS("%s: sending reply: %s\n", __FUNCTION__, err_getstring(*result));
151    return SYS_ERR_OK;
152}
153
154static errval_t mon_ram_alloc(struct capref *ret, uint8_t size_bits,
155                              uint64_t minbase, uint64_t maxlimit)
156{
157    errval_t err;
158    intermon_caprep_t caprep;
159    errval_t reterr;
160
161    err = monitor_mem_client->rpc_tx_vtbl.alloc(monitor_mem_client, size_bits,
162                                        minbase, maxlimit, my_core_id, &reterr,
163                                        (monitor_mem_caprep_t *) &caprep);
164    if (err_is_fail(err)) {
165        return err_push(err, MON_ERR_RAM_ALLOC_ERR);
166    } else if (err_is_fail(reterr)) {
167        return err_push(reterr, MON_ERR_RAM_ALLOC_RETERR);
168    }
169
170    struct capability cap_raw;
171    caprep_to_capability(&caprep, &cap_raw);
172    assert(ObjType_RAM == cap_raw.type);
173
174    err = slot_alloc(ret);
175    if (err_is_fail(err)) {
176        return err_push(err, LIB_ERR_SLOT_ALLOC);
177    }
178
179    err = monitor_cap_create(*ret, &cap_raw, my_core_id);
180    if (err_is_fail(err)) {
181        return err_push(err, MON_ERR_CAP_CREATE);
182    }
183
184    return reterr;
185}
186
187static struct monitor_mem_rpc_rx_vtbl the_monitor_mem_rpc_vtable = {
188    .alloc_call = mem_alloc_handler,
189    .free_call = mem_free_handler,
190};
191
192static errval_t monitor_mem_connected(void *st, struct monitor_mem_binding *b)
193{
194    b->rpc_rx_vtbl = the_monitor_mem_rpc_vtable;
195    return SYS_ERR_OK;
196}
197
198static void monitor_mem_listening(void *st, errval_t err, iref_t iref)
199{
200    if (err_is_fail(err)) {
201        USER_PANIC_ERR(err, "err in monitor_mem_listening failed");
202    }
203    monitor_mem_iref = iref;
204}
205
206errval_t mon_ram_alloc_serve(void)
207{
208    errval_t err;
209
210    err = monitor_mem_export(NULL, monitor_mem_listening, monitor_mem_connected,
211                             get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
212    if (err_is_fail(err)) {
213        return err;
214    }
215
216    return SYS_ERR_OK;
217}
218
219static void bind_cont(void *st, errval_t err, struct monitor_mem_binding *b)
220{
221    if (err_is_fail(err)) {
222        USER_PANIC_ERR(err, "err in bind_cont failed");
223    }
224
225    // setup RPC client above binding
226    monitor_mem_client = b;
227    monitor_mem_rpc_client_init(monitor_mem_client);
228    mem_setup_complete = true;
229}
230
231errval_t mon_ram_alloc_init(coreid_t core_id, struct intermon_binding *b)
232{
233    errval_t err;
234
235    /* Set memcore_id */
236    mem_core_id = core_id;
237
238    // Get service IREF from core
239    err = b->tx_vtbl.monitor_mem_iref_request(b, NOP_CONT);
240    if (err_is_fail(err)) {
241        return err_push(err, MON_ERR_SEND_REMOTE_MSG);
242    }
243    while(monitor_mem_iref == 0) {
244        messages_wait_and_handle_next();
245    }
246
247    // Bind to service
248    err = monitor_mem_bind(monitor_mem_iref, bind_cont, NULL,
249                           get_default_waitset(), IDC_BIND_FLAGS_DEFAULT);
250    if (err_is_fail(err)) {
251        USER_PANIC_ERR(err, "monitor_mem_bind failed");
252    }
253    while(!mem_setup_complete) {
254        messages_wait_and_handle_next();
255    }
256
257    err = ram_alloc_set(mon_ram_alloc);
258    if (err_is_fail(err)) {
259        return err_push(err, LIB_ERR_RAM_ALLOC_SET);
260    }
261
262    return SYS_ERR_OK;
263}
264
265errval_t mon_ram_free(struct capability *cap_raw, genpaddr_t base, uint8_t bits)
266{
267    errval_t err, status;
268    // get caprep
269    intermon_caprep_t caprep;
270    capability_to_caprep(cap_raw, &caprep);
271    // XXX: work around stupid flounder behaviour: these types are identical!
272    monitor_mem_caprep_t caprep2;
273    STATIC_ASSERT_SIZEOF(caprep, sizeof(caprep2));
274    memcpy(&caprep2, &caprep, sizeof(caprep));
275
276    err = monitor_mem_client->rpc_tx_vtbl.free(monitor_mem_client, caprep2, base, bits, &status);
277    if (err_is_fail(err)) {
278        return err;
279    }
280    return status;
281}
282