1/**
2 * \file
3 * \brief Domain management
4 *
5 * \bug This is misnamed. It is "local kernel notification
6 * management", part of which is domain management.
7 */
8
9/*
10 * Copyright (c) 2010, 2011, ETH Zurich.
11 * All rights reserved.
12 *
13 * This file is distributed under the terms in the attached LICENSE file.
14 * If you do not find this file, copies can be found by writing to:
15 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
16 */
17
18#include <barrelfish/barrelfish.h>
19#include <barrelfish/core_state.h>
20#include <barrelfish/dispatch.h>
21#include "monitor.h"
22#include <if/mem_defs.h>
23
24#if !defined(__arm__) && !defined(__aarch64__)
25static errval_t reclaim_memory(genpaddr_t base, uint8_t bits)
26{
27    /* XXX: mem client is only defined for the bsp core.
28     * For app cores, just return */
29    if (get_mem_client() == NULL) {
30        return SYS_ERR_OK;
31    }
32
33    // Fabricate new RAM cap and hand back to mem_serv
34    struct capability c = {
35        .type = ObjType_RAM,
36        .u.ram = {
37            .base = base,
38            .bytes = 1UL << bits,
39        }
40    };
41    struct capref ramcap;
42    errval_t err = slot_alloc(&ramcap);
43    if(err_is_fail(err)) {
44        return err;
45    }
46
47    err = monitor_cap_create(ramcap, &c, my_core_id);
48    if(err_is_fail(err)) {
49        return err;
50    }
51
52    struct ram_alloc_state *ram_alloc_state = get_ram_alloc_state();
53    errval_t result;
54    thread_mutex_lock(&ram_alloc_state->ram_alloc_lock);
55    struct mem_binding *b = get_mem_client();
56    // XXX: This should not be an RPC! It could stall the monitor, but
57    // we trust mem_serv for the moment.
58    err = b->rpc_tx_vtbl.free_monitor(b, ramcap, base, bits, &result);
59    thread_mutex_unlock(&ram_alloc_state->ram_alloc_lock);
60    if(err_is_fail(err)) {
61        return err;
62    }
63    if(err_is_fail(result)) {
64        return result;
65    }
66
67    // XXX: this shouldn't be necessary as free_monitor uses give_away_cap
68    err = cap_destroy(ramcap);
69    if (err_no(err) == SYS_ERR_CAP_NOT_FOUND) {
70        err = SYS_ERR_OK;
71    }
72    if (err_is_fail(err)) {
73        DEBUG_ERR(err, "destroying reclaimed cap");
74    }
75    return err;
76}
77#endif
78
79static void handle_notification(void *arg)
80{
81    struct lmp_endpoint *ep = arg;
82    errval_t err;
83
84    do { // consume messages
85        struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
86        err = lmp_endpoint_recv(ep, &msg.buf, NULL);
87
88        if (err_is_ok(err)) {
89            if(msg.buf.msglen == 1) {
90                domainid_t domid = msg.words[0];
91
92                // XXX: This is done by spawnd now
93                if (domid != 0) {
94                    debug_printf("Dispatcher with domain ID %"PRIuDOMAINID" exited\n",
95                                 domid);
96                }
97            } else if(msg.buf.msglen == sizeof(struct RAM) / sizeof(uintptr_t) + 1) {
98#if !defined(__arm__) && !defined(__aarch64__)
99                //defined(__x86_64__) || defined(__i386__)
100                union rammsg {
101                    uintptr_t msgwords[LMP_MSG_LENGTH];
102                    struct RAM ram;
103                } *u;
104                u = (union rammsg *)&msg.words;
105
106                /* printf("%s.%d: RAM cap deleted, base = %" PRIxGENPADDR ", bits = %u\n", */
107                /*        disp_name(), disp_get_core_id(), ram->base, ram->bits); */
108
109                err = reclaim_memory(u->ram.base, log2ceil(u->ram.bytes));
110                if(err_is_fail(err)) {
111                    DEBUG_ERR(err, "reclaim_memory");
112                }
113#else
114                /* XXX: Disabling memory reclamation on ARM. I
115                 * couldn't get the compiler to accept the above code
116                 * due to strict aliasing restrictions. I do believe
117                 * though that the above is according to the C99
118                 * spec. Please help fix it, so that it can be
119                 * enabled.
120                 */
121#endif
122            } else {
123                printf("%s: Unknown kernel notification of length %zu received\n",
124                       disp_name(), msg.buf.msglen);
125            }
126        } else if (err_no(err) != LIB_ERR_NO_LMP_MSG) {
127            DEBUG_ERR(err, "unexpected error from lmp_endpoint_recv");
128        }
129    } while(err_is_ok(err));
130
131    // re-register
132    struct event_closure cl = {
133        .handler = handle_notification,
134        .arg = arg,
135    };
136    err = lmp_endpoint_register(ep, get_default_waitset(), cl);
137    assert(err_is_ok(err));
138}
139
140void domain_mgmt_init(void)
141{
142    errval_t err;
143
144    /* Register notification endpoint with kernel */
145    struct capref epcap;
146    struct lmp_endpoint *notifyep;
147    // XXX: This has to be huge so we can receive a batch of
148    // notifications when deleting CNodes recursively.
149    err = endpoint_create(100 * 12, &epcap, &notifyep);
150    if (err_is_fail(err)) {
151        USER_PANIC_ERR(err, "failed creating endpoint");
152    }
153
154    // register to receive on this endpoint
155    struct event_closure cl = {
156        .handler = handle_notification,
157        .arg = notifyep,
158    };
159    err = lmp_endpoint_register(notifyep, get_default_waitset(), cl);
160    assert(err_is_ok(err));
161
162    err = invoke_monitor_register(epcap);
163    if(err_is_fail(err)) {
164        USER_PANIC_ERR(err, "Could not register with kernel");
165    }
166    else {
167#ifdef DEBUG_MONITOR_ALL
168        debug_printf("monitor ep registered\n");
169#endif
170    }
171}
172